├── .gitignore ├── gradle ├── gradle-daemon-jvm.properties ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── verification-metadata.xml └── verification-keyring.keys ├── gradle.properties ├── settings.gradle.kts ├── renovate.json ├── src ├── main │ └── java │ │ └── org │ │ └── gradlex │ │ └── javamodule │ │ └── packaging │ │ ├── package-info.java │ │ ├── model │ │ ├── package-info.java │ │ └── Target.java │ │ ├── tasks │ │ ├── package-info.java │ │ ├── ValidateHostSystemAction.java │ │ └── Jpackage.java │ │ ├── internal │ │ ├── package-info.java │ │ └── HostIdentification.java │ │ ├── JavaModulePackagingPlugin.java │ │ └── JavaModulePackagingExtension.java └── test │ └── java │ └── org │ └── gradlex │ └── javamodule │ └── packaging │ └── test │ ├── fixture │ ├── Io.java │ ├── Directory.java │ ├── WritableFile.java │ └── GradleBuild.java │ ├── JavaModulePackagingSmokeTest.java │ ├── JavaModulePackagingResourcesTest.java │ └── JavaModulePackagingOptionsTest.java ├── .github └── workflows │ ├── dependency-submission.yml │ ├── ci-build.yml │ └── release.yml ├── CHANGELOG.md ├── gradlew.bat ├── gradlew ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build 4 | -------------------------------------------------------------------------------- /gradle/gradle-daemon-jvm.properties: -------------------------------------------------------------------------------- 1 | toolchainVersion=17 -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.caching=true 2 | org.gradle.configuration-cache=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gradlex-org/java-module-packaging/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { id("org.gradlex.internal-build-conventions") version "0.8" } 2 | 3 | rootProject.name = "java-module-packaging" 4 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/org/gradlex/javamodule/packaging/package-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | @NullMarked 3 | package org.gradlex.javamodule.packaging; 4 | 5 | import org.jspecify.annotations.NullMarked; 6 | -------------------------------------------------------------------------------- /src/main/java/org/gradlex/javamodule/packaging/model/package-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | @NullMarked 3 | package org.gradlex.javamodule.packaging.model; 4 | 5 | import org.jspecify.annotations.NullMarked; 6 | -------------------------------------------------------------------------------- /src/main/java/org/gradlex/javamodule/packaging/tasks/package-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | @NullMarked 3 | package org.gradlex.javamodule.packaging.tasks; 4 | 5 | import org.jspecify.annotations.NullMarked; 6 | -------------------------------------------------------------------------------- /src/main/java/org/gradlex/javamodule/packaging/internal/package-info.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | @NullMarked 3 | package org.gradlex.javamodule.packaging.internal; 4 | 5 | import org.jspecify.annotations.NullMarked; 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /.github/workflows/dependency-submission.yml: -------------------------------------------------------------------------------- 1 | name: Dependency Submission 2 | 3 | on: [ push ] 4 | 5 | permissions: 6 | contents: write 7 | 8 | jobs: 9 | dependency-submission: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v6 13 | - uses: gradle/actions/dependency-submission@v5 14 | with: 15 | build-scan-publish: true 16 | build-scan-terms-of-use-url: "https://gradle.com/help/legal-terms-of-use" 17 | build-scan-terms-of-use-agree: "yes" 18 | -------------------------------------------------------------------------------- /src/main/java/org/gradlex/javamodule/packaging/tasks/ValidateHostSystemAction.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.gradlex.javamodule.packaging.tasks; 3 | 4 | import static org.gradlex.javamodule.packaging.internal.HostIdentification.validateHostSystem; 5 | 6 | import java.util.Map; 7 | import org.gradle.api.Action; 8 | import org.gradle.api.Task; 9 | 10 | public class ValidateHostSystemAction implements Action { 11 | @Override 12 | public void execute(Task task) { 13 | Map inputs = task.getInputs().getProperties(); 14 | validateHostSystem((String) inputs.get("architecture"), (String) inputs.get("operatingSystem")); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.github/workflows/ci-build.yml: -------------------------------------------------------------------------------- 1 | name: Build Plugin 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | gradle-build: 11 | strategy: 12 | matrix: 13 | os: [ubuntu, macos, windows] 14 | runs-on: ${{ matrix.os }}-latest 15 | steps: 16 | - name: standardize git line endings 17 | run: | 18 | git config --global core.autocrlf false 19 | git config --global core.eol lf 20 | - name: git clone 21 | uses: actions/checkout@v6 22 | - name: Set up JDK 23 | uses: actions/setup-java@v5 24 | with: 25 | distribution: temurin 26 | java-version: 17 27 | - name: Set up Gradle 28 | uses: gradle/actions/setup-gradle@v5 29 | - name: Set up TestLens 30 | uses: testlens-app/setup-testlens@v1.4.0 31 | - run: "./gradlew build" -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Publish Release 2 | on: 3 | push: 4 | tags: 5 | - 'v*' 6 | jobs: 7 | release-build: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: git clone 11 | uses: actions/checkout@v6 12 | - name: Set up JDK 13 | uses: actions/setup-java@v5 14 | with: 15 | distribution: temurin 16 | java-version: 17 17 | - name: Set up Gradle 18 | uses: gradle/actions/setup-gradle@v5 19 | - name: Set up TestLens 20 | uses: testlens-app/setup-testlens@v1.4.0 21 | - run: "./gradlew :publishPlugin --no-configuration-cache" 22 | env: 23 | SIGNING_KEY: ${{ secrets.SIGNING_KEY }} 24 | SIGNING_PASSPHRASE: ${{ secrets.SIGNING_PASSPHRASE }} 25 | GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }} 26 | GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }} -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Java Module Packaging Gradle Plugin - Changelog 2 | 3 | ## Version 1.2 4 | * [Fixed] [#69](https://github.com/gradlex-org/java-module-packaging/issues/69) - Use an args file for 'jpackage' to not exceed command line length limits (Thanks [Oliver Kopp](https://github.com/koppor) for contributing!) 5 | 6 | ## Version 1.1 7 | - Configuration option for `--jlink-options` 8 | - Configuration option for `--verbose` 9 | - Configuration option to build packages in one step (interesting for MacOS signing) 10 | - More options to add custom resources to a package 11 | - Option to explicitly build the 'app-image' folder only (or in addition) 12 | - By convention, set default target to current operating system and architecture 13 | 14 | ## Version 1.0.1 15 | * Do not bind platform-specific assemble tasks to a lifecycle 16 | 17 | ## Versions 1.0 18 | * Initial stable release 19 | 20 | ## Versions 0.1 21 | * Initial features added 22 | -------------------------------------------------------------------------------- /src/test/java/org/gradlex/javamodule/packaging/test/fixture/Io.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.gradlex.javamodule.packaging.test.fixture; 3 | 4 | import java.io.IOException; 5 | import java.io.UncheckedIOException; 6 | 7 | class Io { 8 | 9 | private Io() {} 10 | 11 | static T unchecked(IoSupplier supplier) { 12 | try { 13 | return supplier.get(); 14 | } catch (IOException e) { 15 | throw new UncheckedIOException(e); 16 | } 17 | } 18 | 19 | static void unchecked(T t, IoConsumer consumer) { 20 | try { 21 | consumer.accept(t); 22 | } catch (IOException e) { 23 | throw new UncheckedIOException(e); 24 | } 25 | } 26 | 27 | @FunctionalInterface 28 | interface IoSupplier { 29 | T get() throws IOException; 30 | } 31 | 32 | @FunctionalInterface 33 | interface IoConsumer { 34 | void accept(T t) throws IOException; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/gradlex/javamodule/packaging/model/Target.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.gradlex.javamodule.packaging.model; 3 | 4 | import javax.inject.Inject; 5 | import org.gradle.api.file.ConfigurableFileCollection; 6 | import org.gradle.api.provider.ListProperty; 7 | import org.gradle.api.provider.Property; 8 | 9 | public abstract class Target { 10 | 11 | private final String name; 12 | 13 | public abstract Property getOperatingSystem(); 14 | 15 | public abstract Property getArchitecture(); 16 | 17 | public abstract ListProperty getPackageTypes(); 18 | 19 | public abstract ListProperty getOptions(); 20 | 21 | public abstract ListProperty getAppImageOptions(); 22 | 23 | public abstract ConfigurableFileCollection getTargetResources(); 24 | 25 | public abstract Property getSingleStepPackaging(); 26 | 27 | @Inject 28 | public Target(String name) { 29 | this.name = name; 30 | getSingleStepPackaging().convention(false); 31 | } 32 | 33 | public String getName() { 34 | return name; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/org/gradlex/javamodule/packaging/test/fixture/Directory.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.gradlex.javamodule.packaging.test.fixture; 3 | 4 | import java.io.IOException; 5 | import java.nio.file.Files; 6 | import java.nio.file.Path; 7 | import java.util.Comparator; 8 | import java.util.stream.Stream; 9 | 10 | public class Directory { 11 | 12 | private final Path directory; 13 | 14 | Directory(Path directory) { 15 | this.directory = directory; 16 | Io.unchecked(() -> Files.createDirectories(directory)); 17 | } 18 | 19 | public WritableFile file(String path) { 20 | Path file = directory.resolve(path); 21 | Io.unchecked(() -> Files.createDirectories(file.getParent())); 22 | return new WritableFile(file); 23 | } 24 | 25 | public Directory dir(String path) { 26 | Path dir = directory.resolve(path); 27 | Io.unchecked(() -> Files.createDirectories(dir)); 28 | return new Directory(dir); 29 | } 30 | 31 | public void delete() { 32 | try (Stream walk = Files.walk(directory)) { 33 | walk.sorted(Comparator.reverseOrder()).forEach(p -> Io.unchecked(p, Files::delete)); 34 | } catch (IOException e) { 35 | throw new RuntimeException(e); 36 | } 37 | } 38 | 39 | public Path getAsPath() { 40 | return directory; 41 | } 42 | 43 | public String canonicalPath() { 44 | return Io.unchecked(() -> getAsPath().toFile().getCanonicalPath()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/org/gradlex/javamodule/packaging/test/fixture/WritableFile.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.gradlex.javamodule.packaging.test.fixture; 3 | 4 | import java.nio.file.Files; 5 | import java.nio.file.Path; 6 | import java.nio.file.StandardOpenOption; 7 | 8 | public class WritableFile { 9 | 10 | private final Path file; 11 | 12 | public WritableFile(Path file) { 13 | this.file = file; 14 | } 15 | 16 | public WritableFile(Directory parent, String filePath) { 17 | this.file = Io.unchecked(() -> Files.createDirectories( 18 | parent.getAsPath().resolve(filePath).getParent())) 19 | .resolve(Path.of(filePath).getFileName()); 20 | } 21 | 22 | public WritableFile writeText(String text) { 23 | Io.unchecked(() -> Files.writeString( 24 | file, text, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)); 25 | return this; 26 | } 27 | 28 | public WritableFile appendText(String text) { 29 | Io.unchecked(() -> Files.writeString(file, text, StandardOpenOption.CREATE, StandardOpenOption.APPEND)); 30 | return this; 31 | } 32 | 33 | public void create() { 34 | Io.unchecked(() -> Files.createFile(file)); 35 | } 36 | 37 | public WritableFile delete() { 38 | Io.unchecked(file, Files::delete); 39 | return this; 40 | } 41 | 42 | public boolean exists() { 43 | return Files.exists(file); 44 | } 45 | 46 | public Path getAsPath() { 47 | return file; 48 | } 49 | 50 | public String text() { 51 | return Io.unchecked(() -> Files.readString(file)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/gradlex/javamodule/packaging/JavaModulePackagingPlugin.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.gradlex.javamodule.packaging; 3 | 4 | import javax.inject.Inject; 5 | import org.gradle.api.Plugin; 6 | import org.gradle.api.Project; 7 | import org.gradle.api.file.SourceDirectorySet; 8 | import org.gradle.api.plugins.JavaPlugin; 9 | import org.gradle.api.tasks.SourceSetContainer; 10 | import org.gradle.jvm.toolchain.JavaToolchainService; 11 | import org.gradle.util.GradleVersion; 12 | import org.gradlex.javamodule.packaging.internal.HostIdentification; 13 | 14 | @SuppressWarnings("unused") 15 | public abstract class JavaModulePackagingPlugin implements Plugin { 16 | 17 | @Inject 18 | protected abstract JavaToolchainService getJavaToolchains(); 19 | 20 | @Override 21 | public void apply(Project project) { 22 | if (GradleVersion.current().compareTo(GradleVersion.version("7.4")) < 0) { 23 | throw new RuntimeException("This plugin requires Gradle 7.4+"); 24 | } 25 | 26 | project.getPlugins().apply(JavaPlugin.class); 27 | SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class); 28 | SourceDirectorySet mainResources = sourceSets.getByName("main").getResources(); 29 | 30 | JavaModulePackagingExtension javaModulePackaging = 31 | project.getExtensions().create("javaModulePackaging", JavaModulePackagingExtension.class); 32 | javaModulePackaging.getApplicationName().convention(project.getName()); 33 | javaModulePackaging.getApplicationVersion().convention(project.provider(() -> (String) project.getVersion())); 34 | javaModulePackaging.getJpackageResources().convention(project.provider(() -> project.getLayout() 35 | .getProjectDirectory() 36 | .dir(mainResources.getSrcDirs().iterator().next().getParent() + "/resourcesPackage"))); 37 | javaModulePackaging.getVerbose().convention(false); 38 | javaModulePackaging.primaryTarget(HostIdentification.hostTarget(project.getObjects())); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/gradlex/javamodule/packaging/internal/HostIdentification.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.gradlex.javamodule.packaging.internal; 3 | 4 | import java.util.Locale; 5 | import org.gradle.api.model.ObjectFactory; 6 | import org.gradle.nativeplatform.MachineArchitecture; 7 | import org.gradle.nativeplatform.OperatingSystemFamily; 8 | import org.gradlex.javamodule.packaging.model.Target; 9 | 10 | public class HostIdentification { 11 | 12 | public static void validateHostSystem(String arch, String os) { 13 | String hostOs = hostOs(); 14 | String hostArch = hostArch(); 15 | 16 | if (!normalizeOs(hostOs).equals(normalizeOs(os))) { 17 | wrongHostSystemError(hostOs, os); 18 | } 19 | if (!normalizeArch(hostArch).equals(normalizeArch(arch))) { 20 | wrongHostSystemError(hostArch, arch); 21 | } 22 | } 23 | 24 | public static Target hostTarget(ObjectFactory objects) { 25 | Target host = objects.newInstance(Target.class, "host"); 26 | host.getOperatingSystem().convention(hostOs()); 27 | host.getArchitecture().convention(normalizeArch(System.getProperty("os.arch"))); 28 | return host; 29 | } 30 | 31 | public static boolean isHostTarget(Target target) { 32 | return target.getOperatingSystem().isPresent() 33 | && target.getArchitecture().isPresent() 34 | && target.getOperatingSystem().get().equals(hostOs()) 35 | && target.getArchitecture().get().equals(normalizeArch(hostArch())); 36 | } 37 | 38 | private static String hostOs() { 39 | return normalizeOs(System.getProperty("os.name")); 40 | } 41 | 42 | private static String hostArch() { 43 | return System.getProperty("os.arch"); 44 | } 45 | 46 | private static String normalizeOs(String name) { 47 | String os = name.toLowerCase(Locale.ROOT).replace(" ", ""); 48 | if (os.contains("windows")) { 49 | return OperatingSystemFamily.WINDOWS; 50 | } 51 | if (os.contains("macos") || os.contains("darwin") || os.contains("osx")) { 52 | return OperatingSystemFamily.MACOS; 53 | } 54 | return OperatingSystemFamily.LINUX; 55 | } 56 | 57 | private static String normalizeArch(String name) { 58 | String arch = name.toLowerCase(Locale.ROOT); 59 | if (arch.contains("aarch")) { 60 | return MachineArchitecture.ARM64; 61 | } 62 | if (arch.contains("64")) { 63 | return MachineArchitecture.X86_64; 64 | } 65 | return MachineArchitecture.X86; 66 | } 67 | 68 | private static void wrongHostSystemError(String hostOs, String os) { 69 | throw new RuntimeException("Running on " + hostOs + "; cannot build for " + os); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | 74 | 75 | @rem Execute Gradle 76 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 77 | 78 | :end 79 | @rem End local scope for the variables with windows NT shell 80 | if %ERRORLEVEL% equ 0 goto mainEnd 81 | 82 | :fail 83 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 84 | rem the _cmd.exe /c_ return code! 85 | set EXIT_CODE=%ERRORLEVEL% 86 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 87 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 88 | exit /b %EXIT_CODE% 89 | 90 | :mainEnd 91 | if "%OS%"=="Windows_NT" endlocal 92 | 93 | :omega 94 | -------------------------------------------------------------------------------- /src/test/java/org/gradlex/javamodule/packaging/test/JavaModulePackagingSmokeTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.gradlex.javamodule.packaging.test; 3 | 4 | import static org.gradle.testkit.runner.TaskOutcome.FAILED; 5 | import static org.gradle.testkit.runner.TaskOutcome.SUCCESS; 6 | import static org.gradlex.javamodule.packaging.test.fixture.GradleBuild.hostOs; 7 | import static org.gradlex.javamodule.packaging.test.fixture.GradleBuild.runsOnLinux; 8 | import static org.gradlex.javamodule.packaging.test.fixture.GradleBuild.runsOnMacos; 9 | import static org.gradlex.javamodule.packaging.test.fixture.GradleBuild.runsOnWindows; 10 | 11 | import java.util.Locale; 12 | import java.util.stream.Stream; 13 | import org.assertj.core.api.Assertions; 14 | import org.gradlex.javamodule.packaging.test.fixture.GradleBuild; 15 | import org.junit.jupiter.params.ParameterizedTest; 16 | import org.junit.jupiter.params.provider.Arguments; 17 | import org.junit.jupiter.params.provider.MethodSource; 18 | 19 | /** 20 | * Tests that run on all operating systems and assert success or failure depending on the system they run on. 21 | */ 22 | class JavaModulePackagingSmokeTest { 23 | 24 | GradleBuild build = new GradleBuild(); 25 | 26 | private static Stream testTargets() { 27 | return Stream.of( 28 | Arguments.of("windows", "windows", runsOnWindows()), 29 | Arguments.of("macos", "macos", runsOnMacos()), 30 | Arguments.of("ubuntu", "linux", runsOnLinux())); 31 | } 32 | 33 | @ParameterizedTest 34 | @MethodSource("testTargets") 35 | void can_use_plugin(String label, String os, boolean success) { 36 | var taskToRun = ":app:jpackage" + capitalize(label); 37 | var taskToCheck = ":app:jpackage" + capitalize(label); 38 | var macosArch = System.getProperty("os.arch").contains("aarch") ? "aarch64" : "x86-64"; 39 | build.appBuildFile.appendText( 40 | """ 41 | version = "1.0" 42 | javaModulePackaging { 43 | target("macos") { 44 | operatingSystem.set("macos") 45 | architecture.set("%s") 46 | } 47 | target("ubuntu") { 48 | operatingSystem.set("linux") 49 | architecture.set("x86-64") 50 | } 51 | target("windows") { 52 | operatingSystem.set("windows") 53 | architecture.set("x86-64") 54 | } 55 | } 56 | """ 57 | .formatted(macosArch)); 58 | build.appModuleInfoFile.writeText( 59 | """ 60 | module org.example.app { 61 | } 62 | """); 63 | 64 | var buildResult = success ? build.build(taskToRun) : build.fail(taskToRun); 65 | var taskResult = buildResult.task(taskToCheck); 66 | 67 | Assertions.assertThat(taskResult).isNotNull(); 68 | Assertions.assertThat(taskResult.getOutcome()).isEqualTo(success ? SUCCESS : FAILED); 69 | if (!success) { 70 | Assertions.assertThat(buildResult.getOutput()) 71 | .contains("> Running on %s; cannot build for %s".formatted(hostOs(), os)); 72 | } 73 | } 74 | 75 | private static String capitalize(String str) { 76 | return str.substring(0, 1).toUpperCase(Locale.ROOT) + str.substring(1); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/test/java/org/gradlex/javamodule/packaging/test/JavaModulePackagingResourcesTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.gradlex.javamodule.packaging.test; 3 | 4 | import static org.assertj.core.api.Assertions.assertThat; 5 | import static org.gradlex.javamodule.packaging.test.fixture.GradleBuild.currentTarget; 6 | import static org.gradlex.javamodule.packaging.test.fixture.GradleBuild.runsOnLinux; 7 | import static org.gradlex.javamodule.packaging.test.fixture.GradleBuild.runsOnMacos; 8 | import static org.gradlex.javamodule.packaging.test.fixture.GradleBuild.runsOnWindows; 9 | 10 | import org.gradlex.javamodule.packaging.test.fixture.GradleBuild; 11 | import org.junit.jupiter.api.BeforeEach; 12 | import org.junit.jupiter.api.Test; 13 | 14 | /** 15 | * Tests for adding custom resources to the image/package. 16 | * The tests are OS-dependent and should run on each operating system once. 17 | */ 18 | class JavaModulePackagingResourcesTest { 19 | 20 | GradleBuild build = new GradleBuild(); 21 | 22 | @BeforeEach 23 | void setup() { 24 | var macosArch = System.getProperty("os.arch").contains("aarch") ? "aarch64" : "x86-64"; 25 | build.appBuildFile.appendText( 26 | """ 27 | version = "1.0" 28 | javaModulePackaging { 29 | target("macos") { 30 | operatingSystem.set("macos") 31 | architecture.set("%s") 32 | } 33 | target("ubuntu") { 34 | operatingSystem.set("linux") 35 | architecture.set("x86-64") 36 | } 37 | target("windows") { 38 | operatingSystem.set("windows") 39 | architecture.set("x86-64") 40 | } 41 | } 42 | """ 43 | .formatted(macosArch)); 44 | build.appModuleInfoFile.writeText(""" 45 | module org.example.app { 46 | } 47 | """); 48 | } 49 | 50 | @Test 51 | void can_configure_jlink_options() { 52 | build.appBuildFile.appendText( 53 | """ 54 | javaModulePackaging { 55 | jlinkOptions.addAll( 56 | "--ignore-signing-information", 57 | "--compress", "zip-6", 58 | "--no-header-files", 59 | "--no-man-pages", 60 | "--bind-services", 61 | "--unsupported-option" 62 | ) 63 | } 64 | """); 65 | 66 | // The error shows that all options before '--unsupported-option' are passed through to jlink 67 | var result = build.fail(":app:jpackage"); 68 | assertThat(result.getOutput()).contains("jlink failed with: Error: unknown option: --unsupported-option"); 69 | } 70 | 71 | @Test 72 | void can_configure_add_modules() { 73 | build.appBuildFile.appendText( 74 | """ 75 | javaModulePackaging { 76 | addModules.addAll("com.acme.boo") 77 | } 78 | """); 79 | 80 | // The error shows that the option is passed on to jlink 81 | var result = build.fail(":app:jpackage"); 82 | assertThat(result.getOutput()).contains("jlink failed with: Error: Module com.acme.boo not found"); 83 | } 84 | 85 | @Test 86 | void can_add_resources_for_jpackage() { 87 | // Use 'src/main/resourcesPackage', which is the convention 88 | 89 | // resources that are not known - will be ignored 90 | build.projectDir.file("app/src/main/resourcesPackage/linux/dummy.txt").writeText(""); 91 | build.projectDir.file("app/src/main/resourcesPackage/macos/dummy.txt").writeText(""); 92 | build.projectDir.file("app/src/main/resourcesPackage/windows/dummy.txt").writeText(""); 93 | 94 | // icons will be used 95 | build.projectDir.file("app/src/main/resourcesPackage/linux/icon.png").create(); 96 | build.projectDir.file("app/src/main/resourcesPackage/macos/icon.icns").create(); 97 | build.projectDir.file("app/src/main/resourcesPackage/windows/icon.ico").create(); 98 | 99 | build.build(":app:jpackage"); 100 | 101 | String icon = "app.icns"; 102 | if (runsOnLinux()) icon = "app.png"; 103 | if (runsOnWindows()) icon = "app.ico"; 104 | 105 | // Intermediate location to collect files 106 | assertThat(build.file("app/build/tmp/jpackage/%s/jpackage-resources/dummy.txt".formatted(currentTarget())) 107 | .getAsPath()) 108 | .exists(); 109 | assertThat(build.file("app/build/tmp/jpackage/%s/jpackage-resources/%s".formatted(currentTarget(), icon)) 110 | .getAsPath()) 111 | .exists(); 112 | 113 | // icons end up in Resources 114 | String resourcesFolder = ""; 115 | if (runsOnMacos()) resourcesFolder = "Resources/"; 116 | assertThat(build.appContentsFolder().file(resourcesFolder + icon).getAsPath()) 117 | .hasSize(0); 118 | } 119 | 120 | @Test 121 | void can_add_resources_for_app_folder() { 122 | build.appBuildFile.appendText( 123 | """ 124 | javaModulePackaging { 125 | // resource is added to the os-specific 'app' folder inside the image 126 | resources.from("res") 127 | } 128 | """); 129 | 130 | // resources that are not known - will be ignored 131 | build.projectDir.file("app/res/dummy.txt").writeText(""); 132 | 133 | build.build(":app:jpackage"); 134 | 135 | assertThat(build.appContentsFolder().file("app/dummy.txt").getAsPath()).exists(); 136 | } 137 | 138 | @Test 139 | void can_add_resources_to_image_root() { 140 | // Resource is added to the root of the image. 141 | // This is a target-specific setting as it usually needs to be placed in a place that 142 | // makes sense in the corresponding package structure. 143 | build.appBuildFile.appendText( 144 | """ 145 | javaModulePackaging { 146 | targetsWithOs("windows") { targetResources.from("res") } 147 | targetsWithOs("linux") { targetResources.from("res") } 148 | targetsWithOs("macos") { targetResources.from("res") } 149 | } 150 | """); 151 | 152 | // resources that are not known - will be ignored 153 | build.projectDir.file("app/res/customFolder/dummy.txt").writeText(""); 154 | 155 | build.build(":app:jpackage"); 156 | 157 | assertThat(build.appContentsFolder().file("customFolder/dummy.txt").getAsPath()) 158 | .exists(); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/test/java/org/gradlex/javamodule/packaging/test/fixture/GradleBuild.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.gradlex.javamodule.packaging.test.fixture; 3 | 4 | import static java.util.function.Function.identity; 5 | 6 | import java.io.IOException; 7 | import java.lang.management.ManagementFactory; 8 | import java.nio.file.Files; 9 | import java.nio.file.Path; 10 | import java.util.Arrays; 11 | import java.util.List; 12 | import java.util.stream.Collectors; 13 | import java.util.stream.Stream; 14 | import org.gradle.testkit.runner.BuildResult; 15 | import org.gradle.testkit.runner.GradleRunner; 16 | 17 | public class GradleBuild { 18 | 19 | public final Directory projectDir; 20 | public final WritableFile settingsFile; 21 | public final WritableFile appBuildFile; 22 | public final WritableFile libBuildFile; 23 | public final WritableFile appModuleInfoFile; 24 | public final WritableFile libModuleInfoFile; 25 | 26 | public static final String GRADLE_VERSION_UNDER_TEST = System.getProperty("gradleVersionUnderTest"); 27 | 28 | public GradleBuild() { 29 | this(createBuildTmpDir()); 30 | } 31 | 32 | public GradleBuild(Path dir) { 33 | this.projectDir = new Directory(dir); 34 | this.settingsFile = file("settings.gradle.kts"); 35 | this.appBuildFile = file("app/build.gradle.kts"); 36 | this.appModuleInfoFile = file("app/src/main/java/module-info.java"); 37 | this.libBuildFile = file("lib/build.gradle.kts"); 38 | this.libModuleInfoFile = file("lib/src/main/java/module-info.java"); 39 | 40 | settingsFile.writeText( 41 | """ 42 | dependencyResolutionManagement { repositories.mavenCentral() } 43 | includeBuild(".") 44 | rootProject.name = "test-project" 45 | include("app", "lib") 46 | """); 47 | appBuildFile.writeText( 48 | """ 49 | plugins { 50 | id("org.gradlex.java-module-packaging") 51 | id("application") 52 | } 53 | group = "org.example" 54 | java { 55 | toolchain.languageVersion.set(JavaLanguageVersion.of(17)) 56 | } 57 | application { 58 | mainModule.set("org.example.app") 59 | mainClass.set("org.example.app.Main") 60 | } 61 | """); 62 | file("app/src/main/java/org/example/app/Main.java") 63 | .writeText( 64 | """ 65 | package org.example.app; 66 | 67 | public class Main { 68 | public static void main(String... args) { 69 | } 70 | } 71 | """); 72 | file("app/src/test/java/org/example/app/test/MainTest.java") 73 | .writeText( 74 | """ 75 | package org.example.app.test; 76 | 77 | import org.junit.jupiter.api.Test; 78 | import org.example.app.Main; 79 | 80 | public class MainTest { 81 | @Test 82 | void testApp() { 83 | new Main(); 84 | } 85 | } 86 | """); 87 | 88 | libBuildFile.writeText( 89 | """ 90 | plugins { 91 | id("org.gradlex.java-module-packaging") 92 | id("java-library") 93 | } 94 | group = "org.example" 95 | """); 96 | } 97 | 98 | public WritableFile file(String path) { 99 | return new WritableFile(projectDir, path); 100 | } 101 | 102 | public Directory appImageFolder() { 103 | if (runsOnMacos()) return projectDir.dir("app/build/packages/macos"); 104 | if (runsOnLinux()) return projectDir.dir("app/build/packages/ubuntu"); 105 | if (runsOnWindows()) return projectDir.dir("app/build/packages/windows"); 106 | throw new IllegalStateException("unknown os"); 107 | } 108 | 109 | public Directory appContentsFolder() { 110 | if (runsOnMacos()) return projectDir.dir("app/build/packages/macos/app.app/Contents"); 111 | if (runsOnLinux()) return projectDir.dir("app/build/packages/ubuntu/app/lib"); 112 | if (runsOnWindows()) return projectDir.dir("app/build/packages/windows/app"); 113 | throw new IllegalStateException("unknown os"); 114 | } 115 | 116 | public BuildResult build(String task) { 117 | return runner(task).build(); 118 | } 119 | 120 | public BuildResult fail(String task) { 121 | return runner(task).buildAndFail(); 122 | } 123 | 124 | public GradleRunner runner(String... args) { 125 | return runner(true, args); 126 | } 127 | 128 | public GradleRunner runner(boolean projectIsolation, String... args) { 129 | boolean debugMode = ManagementFactory.getRuntimeMXBean() 130 | .getInputArguments() 131 | .toString() 132 | .contains("-agentlib:jdwp"); 133 | List latestFeaturesArgs = GRADLE_VERSION_UNDER_TEST != null || !projectIsolation 134 | ? List.of() 135 | : List.of("--configuration-cache", "-Dorg.gradle.unsafe.isolated-projects=true"); 136 | Stream standardArgs = Stream.of("-s", "--warning-mode=all"); 137 | GradleRunner runner = GradleRunner.create() 138 | .forwardOutput() 139 | .withPluginClasspath() 140 | .withDebug(debugMode) 141 | .withProjectDir(projectDir.getAsPath().toFile()) 142 | .withArguments(Stream.of(Arrays.stream(args), latestFeaturesArgs.stream(), standardArgs) 143 | .flatMap(identity()) 144 | .collect(Collectors.toList())); 145 | if (GRADLE_VERSION_UNDER_TEST != null) { 146 | runner.withGradleVersion(GRADLE_VERSION_UNDER_TEST); 147 | } 148 | return runner; 149 | } 150 | 151 | private static Path createBuildTmpDir() { 152 | try { 153 | return Files.createTempDirectory("gradle-build"); 154 | } catch (IOException e) { 155 | throw new RuntimeException(e); 156 | } 157 | } 158 | 159 | public static String currentTarget() { 160 | if (runsOnMacos()) return "macos"; 161 | if (runsOnLinux()) return "ubuntu"; 162 | if (runsOnWindows()) return "windows"; 163 | throw new IllegalStateException("unknown os"); 164 | } 165 | 166 | public static boolean runsOnWindows() { 167 | return hostOs().contains("win"); 168 | } 169 | 170 | public static boolean runsOnMacos() { 171 | return hostOs().contains("mac"); 172 | } 173 | 174 | public static boolean runsOnLinux() { 175 | return !runsOnWindows() && !runsOnMacos(); 176 | } 177 | 178 | public static String hostOs() { 179 | String hostOs = System.getProperty("os.name").toLowerCase().replace(" ", ""); 180 | if (hostOs.startsWith("mac")) return "macos"; 181 | if (hostOs.startsWith("win")) return "windows"; 182 | return "linux"; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/test/java/org/gradlex/javamodule/packaging/test/JavaModulePackagingOptionsTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.gradlex.javamodule.packaging.test; 3 | 4 | import static org.assertj.core.api.Assertions.assertThat; 5 | 6 | import org.gradlex.javamodule.packaging.test.fixture.GradleBuild; 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | 10 | /** 11 | * Tests for setting various options for jpackage or the underlying jlink. 12 | * The tests are OS-dependent and should run on each operating system once. 13 | */ 14 | class JavaModulePackagingOptionsTest { 15 | 16 | GradleBuild build = new GradleBuild(); 17 | 18 | @BeforeEach 19 | void setup() { 20 | var macosArch = System.getProperty("os.arch").contains("aarch") ? "aarch64" : "x86-64"; 21 | build.appBuildFile.appendText( 22 | """ 23 | version = "1.0" 24 | javaModulePackaging { 25 | target("macos") { 26 | operatingSystem.set("macos") 27 | architecture.set("%s") 28 | packageTypes.set(listOf("dmg")) 29 | } 30 | target("ubuntu") { 31 | operatingSystem.set("linux") 32 | architecture.set("x86-64") 33 | packageTypes.set(listOf("deb")) 34 | } 35 | target("windows") { 36 | operatingSystem.set("windows") 37 | architecture.set("x86-64") 38 | packageTypes.set(listOf("exe")) 39 | } 40 | } 41 | """ 42 | .formatted(macosArch)); 43 | build.appModuleInfoFile.writeText(""" 44 | module org.example.app { 45 | } 46 | """); 47 | } 48 | 49 | @Test 50 | void can_configure_jlink_options() { 51 | build.appBuildFile.appendText( 52 | """ 53 | javaModulePackaging { 54 | jlinkOptions.addAll( 55 | "--ignore-signing-information", 56 | "--compress", "zip-6", 57 | "--no-header-files", 58 | "--no-man-pages", 59 | "--bind-services", 60 | "--unsupported-option" 61 | ) 62 | } 63 | """); 64 | 65 | var result = build.fail(":app:jpackage"); 66 | 67 | // The error shows that all options before '--unsupported-option' are passed through to jlink 68 | assertThat(result.getOutput()).contains("jlink failed with: Error: unknown option: --unsupported-option"); 69 | } 70 | 71 | @Test 72 | void can_configure_java_options() { 73 | build.appBuildFile.appendText( 74 | """ 75 | application { 76 | applicationDefaultJvmArgs = listOf( 77 | "-XX:+UnlockExperimentalVMOptions", 78 | "-XX:+UseCompactObjectHeaders", 79 | "-Xmx1g", 80 | "-Dsome.prop=some.val" 81 | ) 82 | } 83 | """); 84 | 85 | build.build(":app:jpackage"); 86 | 87 | assertThat(build.appContentsFolder().file("app/app.cfg").getAsPath()) 88 | .hasContent( 89 | """ 90 | [Application] 91 | app.mainmodule=org.example.app/org.example.app.Main 92 | 93 | [JavaOptions] 94 | java-options=-Djpackage.app-version=1.0 95 | java-options=-XX:+UnlockExperimentalVMOptions 96 | java-options=-XX:+UseCompactObjectHeaders 97 | java-options=-Xmx1g 98 | java-options=-Dsome.prop=some.val 99 | """); 100 | } 101 | 102 | @Test 103 | void can_configure_add_modules() { 104 | build.appBuildFile.appendText( 105 | """ 106 | javaModulePackaging { 107 | addModules.addAll("com.acme.boo") 108 | } 109 | """); 110 | 111 | var result = build.fail(":app:jpackage"); 112 | 113 | // The error shows that the option is passed on to jlink 114 | assertThat(result.getOutput()).contains("jlink failed with: Error: Module com.acme.boo not found"); 115 | } 116 | 117 | @Test 118 | void can_set_verbose_option() { 119 | build.appBuildFile.appendText( 120 | """ 121 | javaModulePackaging { 122 | verbose.set(true) 123 | } 124 | """); 125 | 126 | var result = build.build(":app:jpackage"); 127 | 128 | assertThat(result.getOutput()).contains("Creating app package: "); 129 | } 130 | 131 | @Test 132 | void can_set_target_specific_option() { 133 | build.appBuildFile.appendText( 134 | """ 135 | javaModulePackaging { 136 | targetsWithOs("windows") { 137 | singleStepPackaging.set(true) 138 | options.addAll("--dummy") 139 | appImageOptions.addAll("--dummyimg") // no effect due to single-step 140 | } 141 | targetsWithOs("linux") { 142 | singleStepPackaging.set(true) 143 | options.addAll("--dummy") 144 | appImageOptions.addAll("--dummyimg") // no effect due to single-step 145 | } 146 | targetsWithOs("macos") { 147 | singleStepPackaging.set(true) 148 | options.addAll("--dummy") 149 | appImageOptions.addAll("--dummyimg") // no effect due to single-step 150 | } 151 | } 152 | """); 153 | 154 | var result = build.fail(":app:jpackage"); 155 | 156 | assertThat(result.getOutput()).contains("Error: Invalid Option: [--dummy]"); 157 | } 158 | 159 | @Test 160 | void can_set_target_specific_option_for_app_image() { 161 | build.appBuildFile.appendText( 162 | """ 163 | javaModulePackaging { 164 | targetsWithOs("windows") { 165 | options.addAll("--dummy") // no effect as app-image fails first 166 | appImageOptions.addAll("--dummyimg") 167 | } 168 | targetsWithOs("linux") { 169 | options.addAll("--dummy") // no effect as app-image fails first 170 | appImageOptions.addAll("--dummyimg") 171 | } 172 | targetsWithOs("macos") { 173 | options.addAll("--dummy") // no effect as app-image fails first 174 | appImageOptions.addAll("--dummyimg") 175 | } 176 | } 177 | """); 178 | 179 | var result = build.fail(":app:jpackage"); 180 | 181 | assertThat(result.getOutput()).contains("Error: Invalid Option: [--dummyimg]"); 182 | } 183 | 184 | @Test 185 | void can_build_package_in_one_step() { 186 | build.appBuildFile.appendText( 187 | """ 188 | javaModulePackaging { 189 | targetsWithOs("windows") { singleStepPackaging.set(true) } 190 | targetsWithOs("linux") { singleStepPackaging.set(true) } 191 | targetsWithOs("macos") { singleStepPackaging.set(true) } 192 | } 193 | """); 194 | 195 | build.build(":app:jpackage"); 196 | 197 | assertThat(build.appImageFolder().getAsPath()) 198 | .isDirectoryContaining(f -> f.getFileName().toString().contains("app") 199 | && f.getFileName().toString().contains("1.0")); 200 | assertThat(build.appImageFolder().getAsPath()) 201 | .isDirectoryNotContaining(f -> f.toFile().isDirectory()); 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /gradle/verification-metadata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | TRUE 7 | armored 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | 118 | 119 | # Determine the Java command to use to start the JVM. 120 | if [ -n "$JAVA_HOME" ] ; then 121 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 122 | # IBM's JDK on AIX uses strange locations for the executables 123 | JAVACMD=$JAVA_HOME/jre/sh/java 124 | else 125 | JAVACMD=$JAVA_HOME/bin/java 126 | fi 127 | if [ ! -x "$JAVACMD" ] ; then 128 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 129 | 130 | Please set the JAVA_HOME variable in your environment to match the 131 | location of your Java installation." 132 | fi 133 | else 134 | JAVACMD=java 135 | if ! command -v java >/dev/null 2>&1 136 | then 137 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 138 | 139 | Please set the JAVA_HOME variable in your environment to match the 140 | location of your Java installation." 141 | fi 142 | fi 143 | 144 | # Increase the maximum file descriptors if we can. 145 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 146 | case $MAX_FD in #( 147 | max*) 148 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 149 | # shellcheck disable=SC2039,SC3045 150 | MAX_FD=$( ulimit -H -n ) || 151 | warn "Could not query maximum file descriptor limit" 152 | esac 153 | case $MAX_FD in #( 154 | '' | soft) :;; #( 155 | *) 156 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 157 | # shellcheck disable=SC2039,SC3045 158 | ulimit -n "$MAX_FD" || 159 | warn "Could not set maximum file descriptor limit to $MAX_FD" 160 | esac 161 | fi 162 | 163 | # Collect all arguments for the java command, stacking in reverse order: 164 | # * args from the command line 165 | # * the main class name 166 | # * -classpath 167 | # * -D...appname settings 168 | # * --module-path (only if needed) 169 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 170 | 171 | # For Cygwin or MSYS, switch paths to Windows format before running java 172 | if "$cygwin" || "$msys" ; then 173 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 174 | 175 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 | 177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 | for arg do 179 | if 180 | case $arg in #( 181 | -*) false ;; # don't mess with options #( 182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 | [ -e "$t" ] ;; #( 184 | *) false ;; 185 | esac 186 | then 187 | arg=$( cygpath --path --ignore --mixed "$arg" ) 188 | fi 189 | # Roll the args list around exactly as many times as the number of 190 | # args, so each arg winds up back in the position where it started, but 191 | # possibly modified. 192 | # 193 | # NB: a `for` loop captures its iteration list before it begins, so 194 | # changing the positional parameters here affects neither the number of 195 | # iterations, nor the values presented in `arg`. 196 | shift # remove old arg 197 | set -- "$@" "$arg" # push replacement arg 198 | done 199 | fi 200 | 201 | 202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 | 205 | # Collect all arguments for the java command: 206 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 207 | # and any embedded shellness will be escaped. 208 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 209 | # treated as '${Hostname}' itself on the command line. 210 | 211 | set -- \ 212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 214 | "$@" 215 | 216 | # Stop when "xargs" is not available. 217 | if ! command -v xargs >/dev/null 2>&1 218 | then 219 | die "xargs is not available" 220 | fi 221 | 222 | # Use "xargs" to parse quoted args. 223 | # 224 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 225 | # 226 | # In Bash we could simply go: 227 | # 228 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 229 | # set -- "${ARGS[@]}" "$@" 230 | # 231 | # but POSIX shell has neither arrays nor command substitution, so instead we 232 | # post-process each arg (as a line of input to sed) to backslash-escape any 233 | # character that might be a shell metacharacter, then use eval to reverse 234 | # that process (while maintaining the separation between arguments), and wrap 235 | # the whole thing up as a single "set" statement. 236 | # 237 | # This will of course break if any of these variables contains a newline or 238 | # an unmatched quote. 239 | # 240 | 241 | eval "set -- $( 242 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 243 | xargs -n1 | 244 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 245 | tr '\n' ' ' 246 | )" '"$@"' 247 | 248 | exec "$JAVACMD" "$@" 249 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2019 Louis Jacomet 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /src/main/java/org/gradlex/javamodule/packaging/tasks/Jpackage.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.gradlex.javamodule.packaging.tasks; 3 | 4 | import static java.util.Objects.requireNonNull; 5 | import static org.gradle.nativeplatform.OperatingSystemFamily.WINDOWS; 6 | import static org.gradlex.javamodule.packaging.internal.HostIdentification.validateHostSystem; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | import java.nio.file.Files; 11 | import java.nio.file.Path; 12 | import java.security.MessageDigest; 13 | import java.security.NoSuchAlgorithmException; 14 | import java.util.ArrayList; 15 | import java.util.Arrays; 16 | import java.util.List; 17 | import java.util.stream.Collectors; 18 | import javax.inject.Inject; 19 | import org.gradle.api.DefaultTask; 20 | import org.gradle.api.file.ConfigurableFileCollection; 21 | import org.gradle.api.file.Directory; 22 | import org.gradle.api.file.DirectoryProperty; 23 | import org.gradle.api.internal.file.FileOperations; 24 | import org.gradle.api.provider.ListProperty; 25 | import org.gradle.api.provider.Property; 26 | import org.gradle.api.tasks.CacheableTask; 27 | import org.gradle.api.tasks.Classpath; 28 | import org.gradle.api.tasks.Input; 29 | import org.gradle.api.tasks.InputFiles; 30 | import org.gradle.api.tasks.Internal; 31 | import org.gradle.api.tasks.Nested; 32 | import org.gradle.api.tasks.Optional; 33 | import org.gradle.api.tasks.OutputDirectory; 34 | import org.gradle.api.tasks.PathSensitive; 35 | import org.gradle.api.tasks.PathSensitivity; 36 | import org.gradle.api.tasks.TaskAction; 37 | import org.gradle.jvm.toolchain.JavaInstallationMetadata; 38 | import org.gradle.process.ExecOperations; 39 | import org.gradle.process.ExecSpec; 40 | 41 | @CacheableTask 42 | public abstract class Jpackage extends DefaultTask { 43 | 44 | @Nested 45 | public abstract Property getJavaInstallation(); 46 | 47 | @Input 48 | public abstract Property getOperatingSystem(); 49 | 50 | @Input 51 | public abstract Property getArchitecture(); 52 | 53 | @Input 54 | public abstract Property getMainModule(); 55 | 56 | @Input 57 | public abstract Property getVersion(); 58 | 59 | @Classpath 60 | public abstract ConfigurableFileCollection getModulePath(); 61 | 62 | @Input 63 | public abstract Property getApplicationName(); 64 | 65 | @Input 66 | @Optional 67 | public abstract Property getApplicationDescription(); 68 | 69 | @InputFiles 70 | @PathSensitive(PathSensitivity.RELATIVE) 71 | public abstract ConfigurableFileCollection getJpackageResources(); 72 | 73 | @InputFiles 74 | @PathSensitive(PathSensitivity.RELATIVE) 75 | public abstract ConfigurableFileCollection getResources(); 76 | 77 | @InputFiles 78 | @PathSensitive(PathSensitivity.RELATIVE) 79 | public abstract ConfigurableFileCollection getTargetResources(); 80 | 81 | @Input 82 | @Optional 83 | public abstract Property getVendor(); 84 | 85 | @Input 86 | @Optional 87 | public abstract Property getCopyright(); 88 | 89 | @Input 90 | public abstract ListProperty getJavaOptions(); 91 | 92 | @Input 93 | public abstract ListProperty getJlinkOptions(); 94 | 95 | @Input 96 | public abstract ListProperty getAddModules(); 97 | 98 | @Input 99 | public abstract ListProperty getOptions(); 100 | 101 | @Input 102 | public abstract ListProperty getAppImageOptions(); 103 | 104 | @Input 105 | public abstract ListProperty getPackageTypes(); 106 | 107 | @Input 108 | public abstract Property getSingleStepPackaging(); 109 | 110 | @Input 111 | public abstract Property getVerbose(); 112 | 113 | @OutputDirectory 114 | public abstract DirectoryProperty getDestination(); 115 | 116 | /** 117 | * To copy resources before adding them. This allows resource filtering via Gradle 118 | * FileCollection and FileTree APIs. 119 | */ 120 | @Internal 121 | public abstract DirectoryProperty getTempDirectory(); 122 | 123 | @Inject 124 | protected abstract FileOperations getFiles(); 125 | 126 | @Inject 127 | protected abstract ExecOperations getExec(); 128 | 129 | @TaskAction 130 | public void runJpackage() throws Exception { 131 | getFiles().delete(getTempDirectory()); 132 | getFiles().delete(getDestination()); 133 | 134 | String os = getOperatingSystem().get(); 135 | String arch = getArchitecture().get(); 136 | 137 | validateHostSystem(arch, os); 138 | 139 | Directory resourcesDir = getTempDirectory().get().dir("jpackage-resources"); 140 | //noinspection ResultOfMethodCallIgnored 141 | resourcesDir.getAsFile().mkdirs(); 142 | 143 | getFiles().copy(c -> { 144 | c.from(getJpackageResources()); 145 | c.into(resourcesDir); 146 | c.rename(f -> f.replace("icon", getApplicationName().get())); 147 | }); 148 | 149 | String executableName = WINDOWS.equals(os) ? "jpackage.exe" : "jpackage"; 150 | String jpackage = getJavaInstallation() 151 | .get() 152 | .getInstallationPath() 153 | .file("bin/" + executableName) 154 | .getAsFile() 155 | .getAbsolutePath(); 156 | 157 | File appContentTmpFolder = getTempDirectory().get().dir("app-content").getAsFile(); 158 | 159 | // build 'app-image' target if required (either needed for the next step or explicitly requested) 160 | if (!getSingleStepPackaging().get() || getPackageTypes().get().contains("app-image")) { 161 | performAppImageStep(jpackage, resourcesDir); 162 | File appImageFolder = appImageFolder(); 163 | File appRootFolder; 164 | if (os.contains("macos")) { 165 | appRootFolder = new File(appImageFolder, "Contents"); 166 | } else if (os.contains("windows")) { 167 | appRootFolder = appImageFolder; 168 | } else { 169 | appRootFolder = new File(appImageFolder, "lib"); 170 | } 171 | copyAdditionalRessourcesToImageFolder(appRootFolder); 172 | } 173 | 174 | if (getSingleStepPackaging().get()) { 175 | // an isolated folder which is later inserted via '--app-content' parameter 176 | copyAdditionalRessourcesToImageFolder(appContentTmpFolder); 177 | } 178 | 179 | // package with additional resources 180 | getPackageTypes().get().stream().filter(t -> !"app-image".equals(t)).forEach(packageType -> getExec() 181 | .exec(e -> { 182 | e.commandLine( 183 | jpackage, 184 | "--type", 185 | packageType, 186 | "--app-version", 187 | getVersion().get(), 188 | "--dest", 189 | getDestination().get().getAsFile().getPath()); 190 | if (getSingleStepPackaging().get()) { 191 | configureJPackageArguments(e, resourcesDir); 192 | if (appContentTmpFolder.exists()) { 193 | for (File appContent : requireNonNull(appContentTmpFolder.listFiles())) { 194 | e.args("--app-content", appContent.getPath()); 195 | } 196 | } 197 | } else { 198 | e.args("--app-image", appImageFolder().getPath()); 199 | } 200 | for (String option : getOptions().get()) { 201 | e.args(option); 202 | } 203 | })); 204 | 205 | generateChecksums(); 206 | } 207 | 208 | private File appImageFolder() { 209 | return Arrays.stream(requireNonNull(getDestination().get().getAsFile().listFiles())) 210 | .filter(File::isDirectory) 211 | .findFirst() 212 | .get(); 213 | } 214 | 215 | private void copyAdditionalRessourcesToImageFolder(File appRootFolder) { 216 | // copy additional resource into the app-image folder 217 | getFiles().copy(c -> { 218 | c.into(appRootFolder); 219 | c.from(getTargetResources()); 220 | c.from(getResources(), to -> to.into("app")); // 'app' is the folder Java loads resources from at runtime 221 | }); 222 | } 223 | 224 | private void performAppImageStep(String jpackage, Directory resourcesDir) { 225 | getExec().exec(e -> { 226 | e.commandLine( 227 | jpackage, 228 | "--type", 229 | "app-image", 230 | "--dest", 231 | getDestination().get().getAsFile().getPath()); 232 | configureJPackageArguments(e, resourcesDir); 233 | for (String option : getAppImageOptions().get()) { 234 | e.args(option); 235 | } 236 | }); 237 | } 238 | 239 | private void configureJPackageArguments(ExecSpec e, Directory resourcesDir) { 240 | String argsFile = createArgsFile(getModulePath().getAsPath()); 241 | e.args( 242 | "--module", 243 | getMainModule().get(), 244 | "--resource-dir", 245 | resourcesDir.getAsFile().getPath(), 246 | "--app-version", 247 | getVersion().get(), 248 | argsFile, 249 | "--name", 250 | getApplicationName().get()); 251 | if (getApplicationDescription().isPresent()) { 252 | e.args("--description", getApplicationDescription().get()); 253 | } 254 | if (getVendor().isPresent()) { 255 | e.args("--vendor", getVendor().get()); 256 | } 257 | if (getCopyright().isPresent()) { 258 | e.args("--copyright", getCopyright().get()); 259 | } 260 | for (String javaOption : getJavaOptions().get()) { 261 | e.args("--java-options", javaOption); 262 | } 263 | for (String javaOption : getJlinkOptions().get()) { 264 | e.args("--jlink-options", javaOption); 265 | } 266 | if (!getAddModules().get().isEmpty()) { 267 | e.args("--add-modules", String.join(",", getAddModules().get())); 268 | } 269 | if (getVerbose().get()) { 270 | e.args("--verbose"); 271 | } 272 | } 273 | 274 | private String createArgsFile(String modulePathAsPath) { 275 | Path argsFile = getTemporaryDir().toPath().resolve("args.txt"); 276 | List lines = new ArrayList<>(1); 277 | lines.add("--module-path " + modulePathAsPath); 278 | try { 279 | Files.write(argsFile, lines); 280 | } catch (IOException e) { 281 | throw new RuntimeException(e); 282 | } 283 | return "@" + argsFile.toString(); 284 | } 285 | 286 | private void generateChecksums() throws NoSuchAlgorithmException, IOException { 287 | File destination = getDestination().get().getAsFile(); 288 | List allFiles = Arrays.stream(requireNonNull(destination.listFiles())) 289 | .filter(File::isFile) 290 | .collect(Collectors.toList()); 291 | for (File result : allFiles) { 292 | MessageDigest digest = MessageDigest.getInstance("SHA-256"); 293 | byte[] encoded = digest.digest(Files.readAllBytes(result.toPath())); 294 | Files.write( 295 | new File(destination, result.getName() + ".sha256").toPath(), 296 | bytesToHex(encoded).getBytes()); 297 | } 298 | } 299 | 300 | private String bytesToHex(byte[] hash) { 301 | StringBuilder hexString = new StringBuilder(2 * hash.length); 302 | for (byte b : hash) { 303 | String hex = Integer.toHexString(0xff & b); 304 | if (hex.length() == 1) { 305 | hexString.append('0'); 306 | } 307 | hexString.append(hex); 308 | } 309 | return hexString.toString(); 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java Module Packaging Gradle plugin 2 | 3 | [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fgradlex-org%2Fjava-module-packaging%2Fbadge%3Fref%3Dmain&style=flat)](https://actions-badge.atrox.dev/gradlex-org/java-module-packaging/goto?ref=main) 4 | [![Gradle Plugin Portal](https://img.shields.io/maven-metadata/v?label=Plugin%20Portal&metadataUrl=https%3A%2F%2Fplugins.gradle.org%2Fm2%2Forg%2Fgradlex%2Fjava-module-packaging%2Forg.gradlex.java-module-packaging.gradle.plugin%2Fmaven-metadata.xml)](https://plugins.gradle.org/plugin/org.gradlex.java-module-packaging) 5 | 6 | A Gradle plugin to package modular Java application as standalone bundles/installers for Windows, macOS and Linux with [jpackage](https://docs.oracle.com/en/java/javase/21/docs/specs/man/jpackage.html). 7 | 8 | This [GradleX](https://gradlex.org) plugin is maintained by me, [Jendrik Johannes](https://github.com/jjohannes). 9 | I offer consulting and training for Gradle and/or the Java Module System - please [reach out](mailto:jendrik.johannes@gmail.com) if you are interested. 10 | There is also my [YouTube channel](https://www.youtube.com/playlist?list=PLWQK2ZdV4Yl2k2OmC_gsjDpdIBTN0qqkE) on Gradle topics. 11 | 12 | If you have a suggestion or a question, please [open an issue](https://github.com/gradlex-org/java-module-packaging/issues/new). 13 | 14 | # Java Modules with Gradle 15 | 16 | If you plan to build Java Modules with Gradle, you should consider using these plugins on top of Gradle core: 17 | 18 | - [`id("org.gradlex.java-module-dependencies")`](https://github.com/gradlex-org/java-module-dependencies) 19 | Avoid duplicated dependency definitions and get your Module Path under control 20 | - [`id("org.gradlex.jvm-dependency-conflict-resolution")`](https://github.com/gradlex-org/jvm-dependency-conflict-resolution) 21 | Additional metadata for widely-used modules and patching facilities to add missing metadata 22 | - [`id("org.gradlex.java-module-testing")`](https://github.com/gradlex-org/java-module-testing) 23 | Proper test setup for Java Modules 24 | - [`id("org.gradlex.extra-java-module-info")`](https://github.com/gradlex-org/extra-java-module-info) 25 | Only if your (existing) project cannot avoid using non-module legacy Jars 26 | - [`id("org.gradlex.java-module-packaging")`](https://github.com/gradlex-org/java-module-packaging) 27 | Package standalone applications for Windows, macOS and Linux 28 | 29 | [In episodes 31, 32, 33 of Understanding Gradle](https://github.com/jjohannes/understanding-gradle) I explain what these plugins do and why they are needed. 30 | [](https://www.youtube.com/watch?v=X9u1taDwLSA&list=PLWQK2ZdV4Yl2k2OmC_gsjDpdIBTN0qqkE) 31 | [](https://www.youtube.com/watch?v=T9U0BOlVc-c&list=PLWQK2ZdV4Yl2k2OmC_gsjDpdIBTN0qqkE) 32 | [](https://www.youtube.com/watch?v=6rFEDcP8Noc&list=PLWQK2ZdV4Yl2k2OmC_gsjDpdIBTN0qqkE) 33 | 34 | [Full Java Module System Project Setup](https://github.com/jjohannes/gradle-project-setup-howto/tree/java_module_system) is a full-fledged Java Module System project setup using these plugins. 35 | [](https://www.youtube.com/watch?v=uRieSnovlVc&list=PLWQK2ZdV4Yl2k2OmC_gsjDpdIBTN0qqkE) 36 | 37 | # How to use? 38 | 39 | Working example projects to inspect: 40 | - [java-module-system](https://github.com/jjohannes/java-module-system) contains a compact sample and further documentation 41 | - [gradle-project-setup-howto](https://github.com/jjohannes/gradle-project-setup-howto/tree/java_module_system) is a full-fledged Java Module System project setup 42 | 43 | For general information about how to structure Gradle builds and apply community plugins like this one to all subprojects 44 | you can check out my [Understanding Gradle video series](https://www.youtube.com/playlist?list=PLWQK2ZdV4Yl2k2OmC_gsjDpdIBTN0qqkE). 45 | 46 | ## Plugin dependency 47 | 48 | Add this to the build file of your convention plugin's build 49 | (e.g. `build-logic/build.gradle(.kts)` or `buildSrc/build.gradle(.kts)`). 50 | 51 | ``` 52 | dependencies { 53 | implementation("org.gradlex:java-module-packaging:1.2") 54 | } 55 | ``` 56 | 57 | ## Apply and use the plugin 58 | 59 | In your convention plugin, apply the plugin and configure the _targets_. 60 | 61 | ``` 62 | plugins { 63 | id("org.gradlex.java-module-packaging") 64 | } 65 | 66 | javaModulePackaging { 67 | target("ubuntu-22.04") { 68 | operatingSystem = OperatingSystemFamily.LINUX 69 | architecture = MachineArchitecture.X86_64 70 | } 71 | target("macos-13") { 72 | operatingSystem = OperatingSystemFamily.MACOS 73 | architecture = MachineArchitecture.X86_64 74 | } 75 | target("macos-14") { 76 | operatingSystem = OperatingSystemFamily.MACOS 77 | architecture = MachineArchitecture.ARM64 78 | } 79 | target("windows-2022") { 80 | operatingSystem = OperatingSystemFamily.WINDOWS 81 | architecture = MachineArchitecture.X86_64 82 | } 83 | } 84 | ``` 85 | 86 | You can now run _target-specific_ builds: 87 | 88 | ```shell 89 | ./gradlew jpackageWindows 90 | ``` 91 | 92 | ```shell 93 | ./gradlew runWindows 94 | ``` 95 | 96 | Or, for convenience, let the plugin pick the target fitting the machine you run on: 97 | 98 | ```shell 99 | ./gradlew jpackage 100 | ``` 101 | 102 | ```shell 103 | ./gradlew run 104 | ``` 105 | 106 | There are some additional configuration options that can be used if needed. 107 | All options have a default. Only configure what you need in addition. 108 | For more information about the available options, consult the 109 | [jpackage](https://docs.oracle.com/en/java/javase/24/docs/specs/man/jpackage.html) and 110 | [jlink](https://docs.oracle.com/en/java/javase/24/docs/specs/man/jlink.html) 111 | (for `jlinkOptions`) documentation. 112 | 113 | ```kotlin 114 | javaModulePackaging { 115 | // global options 116 | applicationName = "app" // defaults to project name 117 | applicationVersion = "1.0" // defaults to project version 118 | applicationDescription = "Awesome App" 119 | vendor = "My Company" 120 | copyright = "(c) My Company" 121 | jlinkOptions.addAll("--no-header-files", "--no-man-pages", "--bind-services") 122 | addModules.addAll("additional.module.to.include") 123 | jpackageResources = layout.projectDirectory.dir("res") // defaults to 'src/main/resourcesPackage' 124 | resources.from(layout.projectDirectory.dir("extra-res")) 125 | verbose = false 126 | 127 | // target specific options 128 | targetsWithOs("windows") { 129 | options.addAll("--win-dir-chooser", "--win-shortcut", "--win-menu") 130 | appImageOptions.addAll("--win-console") 131 | targetResources.from("windows-res") 132 | } 133 | targetsWithOs("macos") { 134 | options.addAll("--mac-sign", "--mac-signing-key-user-name", "gradlex") 135 | singleStepPackaging = true 136 | } 137 | } 138 | ``` 139 | 140 | ## Using target specific variants of libraries (like JavaFX) 141 | 142 | The plugin uses Gradle's [variant-aware dependency management](https://docs.gradle.org/current/userguide/variant_model.html) 143 | to select target-specific Jars based on the configured [targets](#apply-and-use-the-plugin). 144 | For this, such a library needs to be published with [Gradle Module Metadata](https://docs.gradle.org/current/userguide/publishing_gradle_module_metadata.html) 145 | and contain the necessary information about the available target-specific Jars. 146 | If the metadata is missing or incomplete, you should use the [org.gradlex.jvm-dependency-conflict-resolution](https://github.com/gradlex-org/jvm-dependency-conflict-resolution) 147 | plugin to add the missing information via [addTargetPlatformVariant](https://gradlex.org/jvm-dependency-conflict-resolution/#patch-dsl-block). 148 | 149 | For example, for JavaFX it may look like this: 150 | ``` 151 | jvmDependencyConflicts.patch { 152 | listOf("base", "graphics", "controls").forEach { jfxModule -> 153 | module("org.openjfx:javafx-$jfxModule") { 154 | addTargetPlatformVariant("linux", OperatingSystemFamily.LINUX, MachineArchitecture.X86_64) 155 | addTargetPlatformVariant("linux-aarch64", OperatingSystemFamily.LINUX, MachineArchitecture.ARM64) 156 | addTargetPlatformVariant("mac", OperatingSystemFamily.MACOS, MachineArchitecture.X86_64) 157 | addTargetPlatformVariant("mac-aarch64", OperatingSystemFamily.MACOS, MachineArchitecture.ARM64) 158 | addTargetPlatformVariant("win", OperatingSystemFamily.WINDOWS, MachineArchitecture.X86_64) 159 | } 160 | } 161 | } 162 | ``` 163 | 164 | ## Testing against multiple targets 165 | 166 | > [!WARNING] 167 | > Currently, the following only works in combination with [Blackbox Test Suites configured by the _org.gradlex.java-module-testing_ plugin](https://github.com/gradlex-org/java-module-testing?tab=readme-ov-file#blackbox-test-suites). 168 | 169 | Tests run against the _primary_ target, which is either the local machine you run the build on, or what is configured via `javaModulePackaging.primaryTarget(...)`. 170 | If you want to run the test multiple times against each target you configured, you can configure this as follows: 171 | 172 | ``` 173 | javaModulePackaging { 174 | multiTargetTestSuite(testing.suites["test"]) 175 | } 176 | ``` 177 | 178 | Then, there will be a test task available for each target, such as `testWindows-2022` or `testMacos-14`. 179 | 180 | ## Running on GitHub Actions 181 | 182 | Target-specific _tasks_ such as `assembleWindows-2022` or `assembleMacos-14` only run on the fitting operating system and architecture. 183 | If you want to build your software for multiple targets and have GitHub actions available, you can use different 184 | runners to create packages for the different targets. A setup for this can look like this 185 | (assuming your targets are named: `ubuntu-22.04`, `windows-2022`, `macos-13`, `macos-14`): 186 | 187 | ``` 188 | jobs: 189 | check: 190 | runs-on: ubuntu-latest 191 | steps: 192 | - uses: actions/checkout@v4 193 | - uses: actions/setup-java@v4 194 | with: 195 | distribution: temurin 196 | java-version-file: ./gradle/java-version.txt 197 | - uses: gradle/actions/setup-gradle@v3 198 | - run: "./gradlew check" 199 | 200 | package: 201 | needs: check 202 | strategy: 203 | matrix: 204 | os: [ubuntu-22.04, windows-2022, macos-13, macos-14] 205 | runs-on: ${{ matrix.os }} 206 | steps: 207 | - uses: actions/checkout@v4 208 | - uses: actions/setup-java@v4 209 | with: 210 | distribution: temurin 211 | java-version-file: ./gradle/java-version.txt 212 | - uses: gradle/actions/setup-gradle@v3 213 | - run: "./gradlew assemble${{ matrix.os }}" 214 | - uses: actions/upload-artifact@v4 215 | with: 216 | name: Application Package ${{ matrix.os }} 217 | path: build/app/packages/*/* 218 | ``` 219 | 220 | To avoid re-compilation of the Java code on each of the runners, you can run a 221 | [Gradle remote cache node](https://docs.gradle.com/build-cache-node). 222 | 223 | The [java-module-system](https://github.com/jjohannes/java-module-system) project is an example that 224 | uses GitHub actions with a Gradle remote build cache. 225 | 226 | ## FAQ 227 | 228 | ### How does the plugin interact with the `jpackage` command? 229 | 230 | By default, dhe plugin calls `jpackage` in two steps: 231 | 232 | 1. Build `--type app-image` as a package-type independent image folder. This is where `jlink` is involved. 233 | 2. Build OS-specific packages via `--type `. 234 | This may be called several times for the same target (e.g. `exe` and `msi` on Windows). 235 | 236 | OS-independent options can be configured through the extension: 237 | 238 | ```kotlin 239 | javaModulePackaging { 240 | applicationName = "app" // defaults to project name 241 | applicationVersion = "1.0" // defaults to project version 242 | applicationDescription = "Awesome App" 243 | vendor = "My Company" 244 | copyright = "(c) My Company" 245 | jlinkOptions.addAll("--no-header-files", "--no-man-pages", "--bind-services") 246 | addModules.addAll("additional.module.to.include") 247 | verbose = false 248 | } 249 | ``` 250 | 251 | OS-specific options can be defined inside a target: 252 | 253 | ```kotlin 254 | javaModulePackaging { 255 | target("windows-2022") { // address target by name 256 | options.addAll("--win-dir-chooser", "--win-shortcut", "--win-menu") 257 | } 258 | targetsWithOs("windows") { // all targets of for a certain os 259 | // ... 260 | } 261 | } 262 | ``` 263 | 264 | You can tell the plugin to perform packaging in one step by setting the `singleStepPackaging = true` option on a target. 265 | 266 | # Disclaimer 267 | 268 | Gradle and the Gradle logo are trademarks of Gradle, Inc. 269 | The GradleX project is not endorsed by, affiliated with, or associated with Gradle or Gradle, Inc. in any way. 270 | -------------------------------------------------------------------------------- /src/main/java/org/gradlex/javamodule/packaging/JavaModulePackagingExtension.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | package org.gradlex.javamodule.packaging; 3 | 4 | import static org.gradle.language.base.plugins.LifecycleBasePlugin.BUILD_GROUP; 5 | import static org.gradle.nativeplatform.MachineArchitecture.ARCHITECTURE_ATTRIBUTE; 6 | import static org.gradle.nativeplatform.OperatingSystemFamily.LINUX; 7 | import static org.gradle.nativeplatform.OperatingSystemFamily.MACOS; 8 | import static org.gradle.nativeplatform.OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE; 9 | import static org.gradle.nativeplatform.OperatingSystemFamily.WINDOWS; 10 | 11 | import java.util.Arrays; 12 | import java.util.Collections; 13 | import javax.inject.Inject; 14 | import org.gradle.api.Action; 15 | import org.gradle.api.NamedDomainObjectContainer; 16 | import org.gradle.api.NamedDomainObjectSet; 17 | import org.gradle.api.Project; 18 | import org.gradle.api.Task; 19 | import org.gradle.api.artifacts.Configuration; 20 | import org.gradle.api.artifacts.ConfigurationContainer; 21 | import org.gradle.api.attributes.Attribute; 22 | import org.gradle.api.attributes.Bundling; 23 | import org.gradle.api.attributes.Category; 24 | import org.gradle.api.attributes.LibraryElements; 25 | import org.gradle.api.attributes.Usage; 26 | import org.gradle.api.attributes.java.TargetJvmEnvironment; 27 | import org.gradle.api.file.ConfigurableFileCollection; 28 | import org.gradle.api.file.DirectoryProperty; 29 | import org.gradle.api.model.ObjectFactory; 30 | import org.gradle.api.plugins.ApplicationPlugin; 31 | import org.gradle.api.plugins.JavaApplication; 32 | import org.gradle.api.plugins.JavaPluginExtension; 33 | import org.gradle.api.plugins.jvm.JvmTestSuite; 34 | import org.gradle.api.provider.ListProperty; 35 | import org.gradle.api.provider.Property; 36 | import org.gradle.api.tasks.JavaExec; 37 | import org.gradle.api.tasks.SourceSet; 38 | import org.gradle.api.tasks.SourceSetContainer; 39 | import org.gradle.api.tasks.TaskContainer; 40 | import org.gradle.api.tasks.TaskProvider; 41 | import org.gradle.jvm.toolchain.JavaToolchainService; 42 | import org.gradle.nativeplatform.MachineArchitecture; 43 | import org.gradle.nativeplatform.OperatingSystemFamily; 44 | import org.gradle.testing.base.TestSuite; 45 | import org.gradle.util.GradleVersion; 46 | import org.gradlex.javamodule.packaging.internal.HostIdentification; 47 | import org.gradlex.javamodule.packaging.model.Target; 48 | import org.gradlex.javamodule.packaging.tasks.Jpackage; 49 | import org.gradlex.javamodule.packaging.tasks.ValidateHostSystemAction; 50 | 51 | public abstract class JavaModulePackagingExtension { 52 | private static final boolean MIN_GRADLE_9_0 = 53 | GradleVersion.current().compareTo(GradleVersion.version("9.0.0")) >= 0; 54 | private static final Attribute JAVA_MODULE_ATTRIBUTE = Attribute.of("javaModule", Boolean.class); 55 | private static final String INTERNAL = "internal"; 56 | private static final String JPACKAGE = "jpackage"; 57 | 58 | public abstract Property getApplicationName(); 59 | 60 | public abstract Property getApplicationVersion(); 61 | 62 | public abstract Property getApplicationDescription(); 63 | 64 | public abstract Property getVendor(); 65 | 66 | public abstract Property getCopyright(); 67 | 68 | public abstract ListProperty getJlinkOptions(); 69 | 70 | public abstract ListProperty getAddModules(); 71 | 72 | public abstract DirectoryProperty getJpackageResources(); 73 | 74 | public abstract ConfigurableFileCollection getResources(); 75 | 76 | public abstract Property getVerbose(); 77 | 78 | private final NamedDomainObjectContainer targets = getObjects().domainObjectContainer(Target.class); 79 | 80 | @Inject 81 | protected abstract JavaToolchainService getJavaToolchains(); 82 | 83 | @Inject 84 | protected abstract ObjectFactory getObjects(); 85 | 86 | @Inject 87 | protected abstract Project getProject(); 88 | 89 | /** 90 | * Retrieve the target with the given 'label'. If the target does not yet exist, it will be created. 91 | */ 92 | @SuppressWarnings("unused") 93 | public Target target(String label) { 94 | return target(label, target -> {}); 95 | } 96 | 97 | /** 98 | * Register or update a target with the given 'label'. The 'label' uniquely identifies the target. 99 | * It is used for task names and can be chosen freely. 100 | * Details of the target are configured in the {@link Target} configuration action. 101 | */ 102 | public Target target(String label, Action action) { 103 | Target target; 104 | if (targets.getNames().contains(label)) { 105 | target = targets.getByName(label); 106 | } else { 107 | target = targets.create(label, this::newTarget); 108 | } 109 | 110 | action.execute(target); 111 | return target; 112 | } 113 | 114 | /** 115 | * Configure all targets for the given OS. 116 | */ 117 | @SuppressWarnings("unused") 118 | public void targetsWithOs(String operatingSystem, Action action) { 119 | NamedDomainObjectSet matches = 120 | targets.matching(t -> t.getOperatingSystem().isPresent() 121 | && t.getOperatingSystem().get().equals(operatingSystem)); 122 | matches.all(action); 123 | } 124 | 125 | /** 126 | * Set a 'primary target'. Standard Gradle tasks that are not bound to a specific target – like 'assemble' – use 127 | * this 'primary target'. 128 | */ 129 | @SuppressWarnings("unused") 130 | public Target primaryTarget(Target target) { 131 | SourceSetContainer sourceSets = getProject().getExtensions().getByType(SourceSetContainer.class); 132 | ConfigurationContainer configurations = getProject().getConfigurations(); 133 | 134 | sourceSets.all(sourceSet -> { 135 | // Use this target for target-independent classpaths to make some decision 136 | configureTargetAttributes( 137 | configurations.getByName(sourceSet.getCompileClasspathConfigurationName()), target); 138 | configureTargetAttributes( 139 | configurations.getByName(sourceSet.getRuntimeClasspathConfigurationName()), target); 140 | // Integration for consistent resolution by 'java-module-dependencies' plugin 141 | configurations 142 | .matching(conf -> "mainRuntimeClasspath".equals(conf.getName())) 143 | .all(conf -> configureTargetAttributes(conf, target)); 144 | }); 145 | 146 | return target; 147 | } 148 | 149 | /** 150 | * Set a test suite to be 'multi-target'. This registers an additional 'test' task for each target. 151 | */ 152 | @SuppressWarnings({"unused", "UnstableApiUsage"}) 153 | public TestSuite multiTargetTestSuite(TestSuite testSuite) { 154 | if (!(testSuite instanceof JvmTestSuite)) { 155 | return testSuite; 156 | } 157 | 158 | JvmTestSuite suite = (JvmTestSuite) testSuite; 159 | targets.all(target -> suite.getTargets() 160 | .register( 161 | testSuite.getName() + capitalize(target.getName()), 162 | testTarget -> testTarget.getTestTask().configure(task -> { 163 | task.getInputs().property("operatingSystem", target.getOperatingSystem()); 164 | task.getInputs().property("architecture", target.getArchitecture()); 165 | 166 | ConfigurationContainer configurations = getProject().getConfigurations(); 167 | task.setClasspath(configurations 168 | .getByName(target.getName() 169 | + capitalize(suite.getSources().getRuntimeClasspathConfigurationName())) 170 | .plus(getObjects() 171 | .fileCollection() 172 | .from(getProject() 173 | .getTasks() 174 | .named(suite.getSources().getJarTaskName())))); 175 | task.doFirst(new ValidateHostSystemAction()); 176 | }))); 177 | 178 | return testSuite; 179 | } 180 | 181 | private void newTarget(Target target) { 182 | target.getPackageTypes().convention(target.getOperatingSystem().map(os -> { 183 | switch (os) { 184 | case WINDOWS: 185 | return Arrays.asList("exe", "msi"); 186 | case MACOS: 187 | return Arrays.asList("pkg", "dmg"); 188 | case LINUX: 189 | return Arrays.asList("rpm", "deb"); 190 | } 191 | return Collections.emptyList(); 192 | })); 193 | 194 | ConfigurationContainer configurations = getProject().getConfigurations(); 195 | SourceSetContainer sourceSets = getProject().getExtensions().getByType(SourceSetContainer.class); 196 | 197 | sourceSets.all(sourceSet -> { 198 | Configuration internal = maybeCreateInternalConfiguration(); 199 | configurations.create( 200 | target.getName() + capitalize(sourceSet.getCompileClasspathConfigurationName()), c -> { 201 | c.setCanBeConsumed(false); 202 | setInvisible(c); 203 | configureJavaStandardAttributes(c, Usage.JAVA_API); 204 | configureTargetAttributes(c, target); 205 | c.extendsFrom( 206 | configurations.getByName(sourceSet.getImplementationConfigurationName()), 207 | configurations.getByName(sourceSet.getCompileOnlyConfigurationName()), 208 | internal); 209 | }); 210 | Configuration runtimeClasspath = configurations.create( 211 | target.getName() + capitalize(sourceSet.getRuntimeClasspathConfigurationName()), c -> { 212 | c.setCanBeConsumed(false); 213 | setInvisible(c); 214 | configureJavaStandardAttributes(c, Usage.JAVA_RUNTIME); 215 | configureTargetAttributes(c, target); 216 | c.extendsFrom( 217 | configurations.getByName(sourceSet.getImplementationConfigurationName()), 218 | configurations.getByName(sourceSet.getRuntimeOnlyConfigurationName()), 219 | internal); 220 | }); 221 | 222 | if (SourceSet.isMain(sourceSet)) { 223 | getProject() 224 | .getPlugins() 225 | .withType( 226 | ApplicationPlugin.class, 227 | p -> registerTargetSpecificTasks(target, sourceSet.getJarTaskName(), runtimeClasspath)); 228 | } 229 | }); 230 | } 231 | 232 | private void configureJavaStandardAttributes(Configuration resolvable, String usage) { 233 | resolvable.getAttributes().attribute(Usage.USAGE_ATTRIBUTE, getObjects().named(Usage.class, usage)); 234 | resolvable 235 | .getAttributes() 236 | .attribute(Category.CATEGORY_ATTRIBUTE, getObjects().named(Category.class, Category.LIBRARY)); 237 | resolvable 238 | .getAttributes() 239 | .attribute( 240 | LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, 241 | getObjects().named(LibraryElements.class, LibraryElements.JAR)); 242 | resolvable 243 | .getAttributes() 244 | .attribute( 245 | TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE, 246 | getObjects().named(TargetJvmEnvironment.class, TargetJvmEnvironment.STANDARD_JVM)); 247 | resolvable 248 | .getAttributes() 249 | .attribute(Bundling.BUNDLING_ATTRIBUTE, getObjects().named(Bundling.class, Bundling.EXTERNAL)); 250 | // For integration with 'extra-java-module-info' plugin 251 | resolvable.getAttributes().attribute(JAVA_MODULE_ATTRIBUTE, true); 252 | } 253 | 254 | private void configureTargetAttributes(Configuration resolvable, Target target) { 255 | resolvable 256 | .getAttributes() 257 | .attributeProvider( 258 | OPERATING_SYSTEM_ATTRIBUTE, 259 | target.getOperatingSystem().map(name -> getObjects().named(OperatingSystemFamily.class, name))); 260 | resolvable 261 | .getAttributes() 262 | .attributeProvider( 263 | ARCHITECTURE_ATTRIBUTE, 264 | target.getArchitecture().map(name -> getObjects().named(MachineArchitecture.class, name))); 265 | } 266 | 267 | private void registerTargetSpecificTasks(Target target, String applicationJarTask, Configuration runtimeClasspath) { 268 | TaskContainer tasks = getProject().getTasks(); 269 | 270 | JavaPluginExtension java = getProject().getExtensions().getByType(JavaPluginExtension.class); 271 | JavaApplication application = getProject().getExtensions().getByType(JavaApplication.class); 272 | 273 | TaskProvider jpackage = tasks.register(JPACKAGE + capitalize(target.getName()), Jpackage.class, t -> { 274 | t.getJavaInstallation() 275 | .convention(getJavaToolchains() 276 | .compilerFor(java.getToolchain()) 277 | .get() 278 | .getMetadata()); 279 | t.getOperatingSystem().convention(target.getOperatingSystem()); 280 | t.getArchitecture().convention(target.getArchitecture()); 281 | t.getMainModule().convention(application.getMainModule()); 282 | t.getVersion().convention(getApplicationVersion()); 283 | t.getModulePath().from(tasks.named(applicationJarTask)); 284 | t.getModulePath().from(runtimeClasspath); 285 | 286 | t.getApplicationName().convention(getApplicationName()); 287 | t.getJpackageResources().from(getJpackageResources().dir(target.getOperatingSystem())); 288 | t.getApplicationDescription().convention(getApplicationDescription()); 289 | t.getVendor().convention(getVendor()); 290 | t.getCopyright().convention(getCopyright()); 291 | t.getJavaOptions().convention(application.getApplicationDefaultJvmArgs()); 292 | t.getJlinkOptions().convention(getJlinkOptions()); 293 | t.getAddModules().convention(getAddModules()); 294 | t.getOptions().convention(target.getOptions()); 295 | t.getAppImageOptions().convention(target.getAppImageOptions()); 296 | t.getPackageTypes().convention(target.getPackageTypes()); 297 | t.getSingleStepPackaging().convention(target.getSingleStepPackaging()); 298 | t.getResources().from(getResources()); 299 | t.getTargetResources().from(target.getTargetResources()); 300 | t.getVerbose().convention(getVerbose()); 301 | 302 | t.getDestination() 303 | .convention(getProject().getLayout().getBuildDirectory().dir("packages/" + target.getName())); 304 | t.getTempDirectory() 305 | .convention(getProject().getLayout().getBuildDirectory().dir("tmp/jpackage/" + target.getName())); 306 | }); 307 | 308 | tasks.register("run" + capitalize(target.getName()), JavaExec.class, t -> { 309 | t.setGroup(ApplicationPlugin.APPLICATION_GROUP); 310 | t.setDescription("Run this project as a JVM application on " + target.getName()); 311 | t.getJavaLauncher().convention(getJavaToolchains().launcherFor(java.getToolchain())); 312 | t.getMainModule().convention(application.getMainModule()); 313 | t.getMainClass().convention(application.getMainClass()); 314 | t.setJvmArgs(application.getApplicationDefaultJvmArgs()); 315 | t.classpath(tasks.named("jar"), runtimeClasspath); 316 | }); 317 | maybeAddJpackageLifecycleTask(tasks, target, jpackage); 318 | } 319 | 320 | private void maybeAddJpackageLifecycleTask( 321 | TaskContainer tasks, Target target, TaskProvider targetJpackage) { 322 | // if a task already exists, do nothing to avoid conflciting with other plugins 323 | TaskProvider jpackage; 324 | if (tasks.getNames().contains(JPACKAGE)) { 325 | jpackage = tasks.named(JPACKAGE); 326 | } else { 327 | jpackage = tasks.register(JPACKAGE, t -> { 328 | t.setGroup(BUILD_GROUP); 329 | t.setDescription("Build the package for the current host system"); 330 | }); 331 | } 332 | jpackage.configure(t -> { 333 | if (HostIdentification.isHostTarget(target)) { 334 | t.dependsOn(targetJpackage); 335 | } 336 | }); 337 | } 338 | 339 | private Configuration maybeCreateInternalConfiguration() { 340 | Configuration internal = getProject().getConfigurations().findByName(INTERNAL); 341 | if (internal != null) { 342 | return internal; 343 | } 344 | return getProject().getConfigurations().create(INTERNAL, i -> { 345 | i.setCanBeResolved(false); 346 | i.setCanBeConsumed(false); 347 | }); 348 | } 349 | 350 | private String capitalize(String s) { 351 | return s.substring(0, 1).toUpperCase() + s.substring(1); 352 | } 353 | 354 | @SuppressWarnings("deprecation") 355 | private void setInvisible(Configuration c) { 356 | if (!MIN_GRADLE_9_0) { 357 | c.setVisible(false); 358 | } 359 | } 360 | } 361 | -------------------------------------------------------------------------------- /gradle/verification-keyring.keys: -------------------------------------------------------------------------------- 1 | id 66D7CBFF956830FE9F5A723AFE6C7D77A1CE15A6 2 | uid GradleX Code Signing 3 | -----BEGIN PGP PUBLIC KEY BLOCK----- 4 | 5 | mQINBGL3vDQBEAC06DyZDdCJFMDH2/J7zrbhN5oJmYpM/mkwmOjkHbsIMJRcocz5 6 | 7gYQC8OeMyfs+dkorsrY31UpgMW+efjEZbDKItfbcs+y1iEhQ0fkKKam/lzNyjK0 7 | wb1ew3QPMz6NFPcE9+ZmHpQDV3oHJSdNB2wrVPxrDgyxQE5Qufz4KBgbggY+Mn63 8 | yNPxeo7axeK0GgGzoDMw3Iu/pQCVz6eNMn8+0OKowNiE9U8PyYYNdghrmsFEe9sS 9 | ShS8y6GmEYGz4qErI4TpkG5ZkXuIG1ZEgQlP/BuBrY4AIwkUJADGXowr70JMeeZB 10 | 1oFWa1aTx3iIHBtr2ksVOqOuQRmnFdGcUZnqEebQov+q9ZwAge5l1jHiZqZfxQ6m 11 | oQnj7vK7rIA0FW+IznZ3De3M+vUnL/D5EIChySvsxjWOqaRCF8gCUA+KrR7Rqifl 12 | lndVJc4gLFj/NhBvh0TwNYUu2wAEWVEuN40KFs4GcVymdPvy9nJwGqrPOZ3jqdqT 13 | fOskvrgZJtj75wbSppED9Z+pdHLUc85lC5OzjzgE1qKiBh+cxLUwUgRSDFE797Vt 14 | ucYWH2coJQRh92I40koTYgPBV4chkNMc3R8/Gy7LJNMIJcjS513tPuVawCMJRDYO 15 | vz5BSWCgfily85jLX8eK2ceYt1m7OUA8LOElxmzysCGbARgP+lpCMfvHeQARAQAB 16 | tCdHcmFkbGVYIENvZGUgU2lnbmluZyA8dGVhbUBncmFkbGV4Lm9yZz4= 17 | =5N7Z 18 | -----END PGP PUBLIC KEY BLOCK----- 19 | 20 | id 1BD97A6A154E7810EE0BC832E2F38302C8075E3D 21 | uid Gradle Inc. 22 | -----BEGIN PGP PUBLIC KEY BLOCK----- 23 | 24 | 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 59 | =Rl7p 60 | -----END PGP PUBLIC KEY BLOCK----- 61 | 62 | id B02137D875D833D9B23392ECAE5A7FB608A0221C 63 | uid Robert Scholte 64 | -----BEGIN PGP PUBLIC KEY BLOCK----- 65 | 66 | mQMuBFKTz1wRCADOdMCDOKXlBuQpG7mnQ/5rppqhS0SXdKvNZ5pYrJKib1LLtlS/ 67 | LOeABja3E1ky+znvTqnEEtai7fNhw36zPdUjhPKE0TZwn2aK5fyctkcfqBFsja3E 68 | ntJgzi4pa6gVn+MtIjCak71jv5SrC+LE0dkPM/GwupgPL7Ohfpf7HyAGjlpKihrQ 69 | syg6GmkpZKlhLVD+wg+nILrWngXS6Zz2I9M1rd6wfYVqH8tjYkKYNlexB4hL26zt 70 | f2MKX1MTRpdgO/jPEh8EI4K5qg0eT2x2e6qsii50WobmvraZfUFpQJysJlmt5jwe 71 | k/FWfxZ7Hlys8r88VYGa6sknvofGZfhFRZRbAQDhMzmNSQ0mBoveEA8/gd0FqVA+ 72 | YzX8TY90YNeRQMjXJQgAt3kbBz6uyzAchGxSCyZpnS2dVFWqi6H8gqMjKmEnDn+g 73 | vG19F3STuAKYkJPfJZGwAVnZtTbqQ4R14WgjDuoqHPuFjRw5xrIaEVmb71gFKISP 74 | F8RIMw2jWygNeXbbXjRF2brEV4H+V6JXn6PnzlmBLIiB1zhzutMUu50FxnmclQxa 75 | gUxGMcZG/6PcQtiuhu9oKHUl1+E1fs/pexnsPK2gKkRdyUMnngHJ3aYm9vBFMWya 76 | draOg/6DBRTrvgoOVxzQHSFCSs9ttaHXbLDMD1e9K6DnVMKZVHdJVohNVwxsWxrh 77 | ibUDu0iH4Zp5MFgyx9L2kkP9kbL1hflIsTyQehDUwAgAwl/BklUfuOkw64xNZ9ww 78 | YZ/y4GTNuoDIdVkSArr0cKhiLR3u2Qsgy/K2CW5iuXMQGPBrYFfxcHO1Lge5Mvyt 79 | uYhLYvnH7gwfID/8r5Tjx7ktzoZehO2R4wfqyYfKwLoJGY19uj8hCBmKss3GOK7M 80 | JKLDKLZ3Lv0t4MTiaSmVsZEVRwYD3x70J7l3mUUwVHAK0QeKg9RczJQRd/i0lKzt 81 | OAA/d4gZYscWHbZi0dH/KxnqHzSUDkrLuWrYSdvgaln5tS9hG1ge0LFDxf82f1U9 82 | +ckdxzYsu5FNjgu8GFZLbLshRri0kKPWqTBX/YPubApadVU94i0eXnqjmZMajXTm 83 | LbQlUm9iZXJ0IFNjaG9sdGUgPHJmc2Nob2x0ZUBhcGFjaGUub3JnPrkCDQRSk89c 84 | EAgAjxMmDMl2ElKXFXgWpsITsNUuxm3MwQV0oRBDA6YSgLxpf0FqHh0+5W2owt// 85 | Wnr7jjPF9xmyapTwkEUJr7W/m8XYM5e/VraPJdruYI9D8PTxbiLheUfVjXvds65F 86 | K55Fg2pj3tNFTDY1sUcWjvxW1sqlRJpumALTNKLEUSXeFTokHmRyZ8knEIc/0Giy 87 | DIw1aQ+q+BNDwE7hUP0C6CP7Ddtg1nVxPJhn1WdqzM+hPzO1thUyEQTGRtoskVV+ 88 | jYUXyU8iK5WSoNiGoxLCIWiqaC3BuzMb+Q8//zwYdcWC36UZqSpIKuJVmGulQVxO 89 | /1bFuQsHqa4ovGmITRO+D/I39wADBQf+OlVr0544kUJspemRYSkNP4zQtvFCmUW6 90 | 6diQNxrHTHkOkHQeJbx9S0LvuZoL7nleAbKGoPEAD+lgF7jpHV4JrhmSLih1Ocuw 91 | 3gcnhrJws/+jUcFZPtarJ1pEgBQdCxZO9sc0/MG3j1Z1zB/EA7KN5w3Xbh9f1VrG 92 | ar4G6ZXkIcdRPb7Ka8WwfKAVkpU8j4zpY0rV7ilbUY8liYeccw0wCjUYF/8Ww5Tj 93 | 8/dP9i7G0hutvbFQFCWKfJ8pIF3QZsV4nl+mjzXpsG2kTpqj1dRWadYFKf9KBw2e 94 | mi3T/GwAXdGVcwbo2QLD5OqILmdmlWtHo1bsxRiUY3ALKcsV/XrfhIhhBBgRCAAJ 95 | BQJSk89cAhsMAAoJEK5af7YIoCIckdQA/37R5B1w9Xr816QBoNrJIRSKXoaqqt0n 96 | vvzB6IAo6+u3AQDURXWfVKKr73oZFosnOt63VHnW6BV9mMqjj3wenu9FlQ== 97 | =Kqmv 98 | -----END PGP PUBLIC KEY BLOCK----- 99 | 100 | id 4857D1CE04E78FAB2A172E8F39B48E1BADDB933F 101 | uid GradleUp (GradleUp sonatype key) 102 | -----BEGIN PGP PUBLIC KEY BLOCK----- 103 | 104 | xsBNBGE/hA0BCAC+MEPPNI9edKJ8TTplIvVa4o5Umd89fWtwhkxOaenN6y07L9iV 105 | rI2RISRdv73Kc+K+Qb1Vlom4Fa9R4+NAibhb/QRsn1LkA02Z6JIF9w78JN9DBesS 106 | 090TiQwZMzgljJaLVIxzCZk6T9XlZQC3bXmkyZkYS/a9NMa7JnXrPua06JKpH9vZ 107 | cM6L4TUb0p6Tw7RsdBHKBj895XqIVlqJXfNEpcOZ2LCMUcVaOJFS/dAXSrTmNdT1 108 | z1eoeoob/CbHIzH3STWVCXnXOw9APOry+aPpBHAD9g+1Q1BEj8pSmEnByjeO6yHN 109 | UMbFTUtM77oVAbLx6rHL7jzfgUQdVPr8PgU3ABEBAAG0NUdyYWRsZVVwIChHcmFk 110 | bGVVcCBzb25hdHlwZSBrZXkpIDxtYXJ0aW5AbWJvbm5pbi5uZXQ+zsBNBGE/hA0B 111 | CADaDvPtymFgLSJLHPCRIUATJNwKu06QIE1nJ9EiCzHn6HfKm9EvY48g8ovfziQi 112 | bleP7MKllhUXm/ZAN8/ufg3/kRD0KI4aFyToiJtvBOweSfOj/USgC2nSDh7BcZXn 113 | dVkSafrjsrFMdk2sFDiTNi+Qv+BULC3m1ciG0AQyGYQIiGMZnKpTDP6aHZUZTFTB 114 | h9JRXWhjTG4xO3WadRKYAUN879tp73KMACuaI0tK99fLEN/bMMmd9cxBTpZztDnd 115 | PnVlLVyFZGTmjdJKCMcLC/gnixiRpLoy7qXzj9z/nrlZ3QcAPgGKtM+AO37Zsbbn 116 | Qox+Yao0o+GvycRCtNT4OcaTABEBAAHCwHYEGAEIACAWIQRIV9HOBOePqyoXLo85 117 | tI4brduTPwUCYT+EDQIbDAAKCRA5tI4brduTP5/RB/9YiKJTWHr0PRVtV8STKvFm 118 | gMVw+RF+eig5vZ/MKq0svyfeFLf7i/XfndEG4X85G169tvNI7MG8d362NdpSwEdJ 119 | ekiQh4+i5oE5ZdnNDvPXr2pVAKDhyuyPuMUmA0Zf+JWDQ5vfzgpcxos3Y3i2D1D5 120 | 92BDms675Ob18NvjjAMNR9bf0vEmjlv/k5oWUe0lYEDOBnImGgEIPqEOOvKrXZFT 121 | klXcR/JI0sUwvNWLfAsyi3HtnR8r9n26tyo0wCBVWO+zXjvI7xhvpS6bvI1CfeQ0 122 | 04CuCUoP619vciqXdyso5jTobWTXxKvMHgrbw0XAZVlL53qp1OUWi1pA2/eQRMdY 123 | =Sqth 124 | -----END PGP PUBLIC KEY BLOCK----- 125 | 126 | id E7DC75FC24FB3C8DFE8086AD3D5839A2262CBBFB 127 | uid Kotlin Libraries Release 128 | -----BEGIN PGP PUBLIC KEY BLOCK----- 129 | 130 | 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 276 | =9e+M 277 | -----END PGP PUBLIC KEY BLOCK----- 278 | 279 | id 05F1A5DA5701D415BEFC67FC6329ADE2B25B244B 280 | uid Paul de Vrieze 281 | -----BEGIN PGP PUBLIC KEY BLOCK----- 282 | 283 | xsBNBGB9fcABCADNbbtAiTtnUYkhQPik50gYwTuP4QIQjTVeQDBIcwRIjhGMUVov 284 | PD+Tf41NTy9VKlbuQeFIPrx+MzT0V3B+c7KSFXEyi36LzeACDpcDjR3Dzh+cAKGg 285 | acaxk0lsfARgcnCtayPY+rUaZyuJDd/681onRm52GqpkNbCQ4Ikij153VguPcKM3 286 | vPCmckEHtrcbZZbgsH14A9+AQfL599QDJ5XkQv4g3KXVgBAODJrVjjRiVbTNSqJu 287 | gTQsEe1JDSSDv7vYiDmWBdtC1Qbw0IRpuxPLnF0CzNO4gBbWQF+1YN6p5cxpPaae 288 | Q1qMDePS2nLJfcuCEFrIwBG3fGzvmJzh9FHpABEBAAG0KFBhdWwgZGUgVnJpZXpl 289 | IDxwYXVsLmRldnJpZXplQGdtYWlsLmNvbT7OwE0EYH19wAEIANt8dkaPfHGJS38o 290 | m9vEKcS9XJckGHv79xnppCfSEw+S8vjjCR6UZ59YRJRT+8fhSCIE4+yqBpKAXV+p 291 | ElskkJlidvSA+Yu1O+VeZvXhNpGdWMse8obUULf1+JbxaNCmhCUbXoqCZ0MDJvep 292 | ulFOmMTHs4Vh3P6DcgKNpyvOSiEfspY9GwxBbWfirYwjg+wdw/RW00F49vtSL3ax 293 | R9p5DYDWDEhLIuC/yvbDxKeTvICzTB2uQhysONzYUeoqtucE63//gXvdftv34S8w 294 | JgB/3a3S9NzbrAsgRi8QwEole+lKToyNh6CuN+KzYeA4XcvwGIwU5bAAKkY2CRuo 295 | pqSEqhEAEQEAAcLBrAQYAQgAIBYhBAXxpdpXAdQVvvxn/GMpreKyWyRLBQJgfX3A 296 | AhsuAUAJEGMpreKyWyRLwHQgBBkBCAAdFiEEbvTCO4JEqDcAI8Q/P6y0emrmi3wF 297 | AmB9fcAACgkQP6y0emrmi3y7fAf/Zgb+4gbdTycXSG+JmUGzfapgpXtjnNKd5sWG 298 | BW7mGkvfyKIaML3NUKUYz+BQicF9rxnPNm74PM9vl2W3ejY0LXGllk8nJHQTqbNr 299 | YSLMGDTZk9oH3DtaFFImu/XF2etU3OFruqp9WBbr95YCz7TaqsNKfiK8U8PBAShn 300 | 8BcmN9The1XpypVxXdBAiKkX8rZQ31T0eaw/JF1esjMEa741gybgz70Y9oxI8xiO 301 | 7zIj1fr9n3aNns8jmZ3InFI1IA5FI1zg0wAXKAdFbW5crf9osD1WkwIyO21XLWkh 302 | 7goj1A/I/JQAxWZiL7dUpbmtKngVJOaJlSPfbW4zhvsneusYJkkQB/96/b/zyT9V 303 | LXKqwatZF6JXJmG9tEZD6EOEXYV1xfdKMEV6aaiFMN75O6iTTdXs+DBsHeBGUhd7 304 | YvoF2OBVTNKwyAQw8Vtt3edx0LJPZZLk2JoVyQDKW3hmZS8fq+WZg6wgL3PFY227 305 | jzXHWuZ/FPtJRBa/QXJLV8DeQDPGM42ds5nzWk/AegT+nw8jsgznVubRkdjhBT7C 306 | oVADwp4ucWwH/q/05xBqQnv4WdA8QZirLrRqjhQJiA+sMkIHC7b83Q7KrEpSbUGz 307 | rXfNOAUjWjYEM11ek3EKUScDr+hyP7IW6pqf6Le1rHjDQt3PT7zL4LogfL3Rt6GP 308 | Fu69UuSeTPOL 309 | =LH1+ 310 | -----END PGP PUBLIC KEY BLOCK----- 311 | 312 | id 7B79ADD11F8A779FE90FD3D0893A028475557671 313 | uid Gradle Inc. 314 | -----BEGIN PGP PUBLIC KEY BLOCK----- 315 | 316 | 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 350 | WzZKkqBVoahM3qqyoKOy7mfpt1hB4gEq 351 | =E5AV 352 | -----END PGP PUBLIC KEY BLOCK----- 353 | 354 | id FF6E2C001948C5F2F38B0CC385911F425EC61B51 355 | uid Marc Philipp 356 | -----BEGIN PGP PUBLIC KEY BLOCK----- 357 | 358 | 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 392 | PXCe8La72ukmaxEGbpJ8mdzS2PJko7mm 393 | =Xe8l 394 | -----END PGP PUBLIC KEY BLOCK----- 395 | 396 | id 2DB4F1EF0FA761ECC4EA935C86FDC7E2A11262CB 397 | uid Gary David Gregory (Code signing key) 398 | -----BEGIN PGP PUBLIC KEY BLOCK----- 399 | 400 | mQENBE2kzuwBCACYV+G9yxNkSjAKSji0B5ipMGM74JAL1Ogtcu+993pLHHYsdXri 401 | WWXi37x9PLjeHxw63mN26SFyrbMJ4A8erLB03PDjw0DEzAwiu9P2vSvL/RFxGBbk 402 | cM0BTNXNR1rk8DpIzvXtejp8IHtD1qcDLTlJ8D0W3USebShDPo6NmMxTNuH0u99B 403 | WHCMAdSa34wsg0ZpffwQmRxeA+ebrf2ydKupGkeZsKjkLlaXNkTVp1ghn5ts/lvg 404 | KeHv1SJivWKCRmFlbPhBK4+mxSUSOPdoBNAfxA51QzZoPizSk0VbRz3YufYRVLFy 405 | 9vqPSorDmYJhCvn3f6+A38FS/j8VE+8obQ2rABEBAAG0O0dhcnkgRGF2aWQgR3Jl 406 | Z29yeSAoQ29kZSBzaWduaW5nIGtleSkgPGdncmVnb3J5QGFwYWNoZS5vcmc+uQEN 407 | BE2kzuwBCACzeGpkd6X/xTfKDBWvXgHOOKIJ2pht9XmtZZKiIj7LIiSwvSds/Zko 408 | ZKxAm7AY+KPh8Xjf968FtoUBQJvHAG4rbowEqT7OOrJae2JcenH5qzaod7TpIPQV 409 | v+Ysz8I1wLlC6LzKRj1X99Hng6X+obsEasnPbmEEkuiZ/Sgi4vVC8SHkDmYt1Dx8 410 | jDgm53oUeWkEJO9LSI2zcrZhSgvg1xa4Q4gY5UUK7gE4LbmGCjFlATuuW/0sryxu 411 | 8zxph15gkn4Nqgk0CPMSjesMYEGOsdDzfQXl2tXbt+Pe6mBoWh67MZ1v5zOq3EDt 412 | oSqDpWPxponAeaCuNDDFX44vGjfxGE0tABEBAAGJAR8EGAECAAkFAk2kzuwCGwwA 413 | CgkQhv3H4qESYsvEMAf/VGyqIEcw4T2D3gZZ3ITkeoBevQdxBT/27xNvoWOZyGSz 414 | GYlRbRQrlo+uZsjfMc9MNvaSmxyy4gLVbcdvQr3PF//GxphJ98W8pk9l+M57jfyH 415 | nnCumn7MO4o9ed+WuigN5oeuNJ6BIq3ff2o1DsrEvDChYOJEOeFuWxv+u7I2ABJJ 416 | ep7NbByM2n9PE8vlGU3zUBgWUBsk6jT+klKnEyHE76WzegPLz3jtElTuyB7jRhjy 417 | QJu1yiJEMbs2zH8aJGObi5f8Jum4tILZuEAdoI0M3c3VRq12cz/vLy+9VXa/s//8 418 | IsGn88kjyyYqOy8WJEjoOXFh++dpWiM7nZkgQcNi5A== 419 | =ggBv 420 | -----END PGP PUBLIC KEY BLOCK----- 421 | 422 | id 4DB1A49729B053CAF015CEE9A6ADFC93EF34893E 423 | uid Tom Denley (scarytom) 424 | -----BEGIN PGP PUBLIC KEY BLOCK----- 425 | 426 | xsBNBE+xZxIBCACzKctn4ez8xOC0pGThhAwjYWGkzcwK4HNaC1usHThBFz3/t8JN 427 | OqUXRixLyi5wELN6GHlsGVUQS3IfB4JtuhScsieSB8PTree68/knMq6JI08mJqZr 428 | 9nFrAB4eDW0UMbSL9kPmclUm/yN+qcCZBrsVn0q6CWb/Kcd8EEXEu6sGILzOGqGe 429 | d433t5O+tGXWL2TjAz+Scsk2Hf4zcuDeQcxELAMnVaVgKuGuEZvibrjsdIvJDGI+ 430 | 0BzWIu8ZP8ldBl4SVtzGpEVzLvDUo3mOqBeTkj3rP7xLtFDN/3AFtowbLfL7L2Pg 431 | SMcTnKK+jfFHRfbHP1Ih3rQ4ilLzhCnY/QIZABEBAAG0K1RvbSBEZW5sZXkgKHNj 432 | YXJ5dG9tKSA8dC5kZW5sZXlAY2FudGFiLm5ldD7OwE0ET7FnEgEIAM3i3e1sjwrx 433 | 2PN8XYMPQWG+/YTtw1BYDl2+iYE+LaZvtq1hpbgeCLgEVwXrCJ4spLP1rFXogWqK 434 | rkJ0LRjlpdKhKBvyH1ex4grh3cWN/bIDJcJ7JA4I/Bhqhlh8hYycS9pGFeS+MR3a 435 | FIsii+vadrwYYvuVYGeWvdZhB7mJKYevj5Ms0OpYTfZd95Pzo4o//lNpDnrG7Xd3 436 | tgTNU/fkpw6rFB/2Ib1Qlk+Kz1z6JNsp+tOPGGCBrzwfwglcikTuqS+xyRgC9cHh 437 | 5eCol11uSoWPKcQR2Ar8Eo56nxv/UApdu15iJ7R8cA5guKeeS4jt0CGCPs2Phugg 438 | DxI73Xvl4zsAEQEAAcLAXwQYAQIACQUCT7FnEgIbDAAKCRCmrfyT7zSJPuylB/9i 439 | wtIQeexMWBmQNdDe0md8HLulDfcujPtklrvYHtXMJQFaGA0Vafq0oT9MhBfb1YCP 440 | 79uF0qgswSxINYCOJx4nTPIP9BOdTwqfGo7ul27REgNq4lIUW0GkMgZAUA2ft/vc 441 | 0u/I0PqnhKCi4Pq79hLIx7eiX2ySfXfYfLXRVzbMWKMoi7lWXseQqbM0RvCA54J1 442 | qAi6Ew+JyoYGQ7OvXdL5Eh5Tkm2cpIADyqCkp/aFDe5lqZiU1zS2fU6mpOf/o0co 443 | +GoYkieIxxibDCmt3BioLgmyzpGUsMNwh4pAIQUGkcxd4spC0KIWdDEvq/QJEEIh 444 | ZlI/ojefaZkRseFrtl3X 445 | =L0GY 446 | -----END PGP PUBLIC KEY BLOCK----- 447 | 448 | id EA022560A81E5BD48DB3D18B54AC8E2D98CFEAC6 449 | uid gitlab@ysb33r.org 450 | -----BEGIN PGP PUBLIC KEY BLOCK----- 451 | 452 | mQGNBGB1tD4BDADSzOETLscSpqNTDixnOsYLLwodQQ6pxebc4w4s2QarDHvdaFft 453 | lZge0kTQCxpvGiENusWwt6gQngegy6qWziWSfbdHgVWBsH5u9frgJ8wCZ21UqEwV 454 | A3d/rEbzpc3Ujo1L3yFpuZJWpBo4jTwH3GGxNXS64VwKN/mAKFZirm9DrSpdNjQU 455 | S0mlOThn/SdJ4jqH2podnRZs3yxlr33NvVAYaACndLABCTMkHqKTRPhFYR2C2XAV 456 | sMQ0sQaYJLmMHUTB2Cn8FZRudhuBl+O3TY58w77h+EoUrSw8T4aQRZn9Lbuq1voL 457 | 3onEnoR9tU06P576wjrJ44KGi4YJz/L5yKreKBfSe7vfGhBWDmrcjSb3thj+pP30 458 | Q7LQFmY5EaAz/Wpr0oDMAxtBBbii+QCllEFxu397OMrZZYqQjt9K/l4krYjDZc12 459 | fQZqCT889kRBA8nqhPpueY5iELmL5oGHTKmWDbKFo6fEPAq6F3e9p50s9pfhT1g2 460 | GUM9m+0LDs+N+38AEQEAAbQRZ2l0bGFiQHlzYjMzci5vcme5AY0EYHW0PgEMALkB 461 | cL/X7eKvtznC1SE4dJr0skc9rGniiYwVhSNiyiYXlbb0ETdRDbajSHjv53cR5DGb 462 | AyPgwwLNzHo1K3MrE0CvM09sCMJBOjpCu1X5sma1w76I9ScvJ+Gqr3jFu8CO9JbS 463 | s4bj2VRr9ITOEZinvwo+Ult1vj1Vib9K4lAlpsXcd0dgFS7jlTBqeDgRR+xyRdt+ 464 | 54yrCay+IXupBF0GuYQ9lHwCVyFhwhOneoQq4xhEmwmNEQOWq28byVLUpMDzKAPt 465 | +T5AmyxNebLRQmE7rWX2PmoCSTby8aQPlG0OSRBQJu3f6lhMZN21QbTcCBeDW5VI 466 | sjPtZnJ7nIpOkT2UXulnlRk/QAEydJdPdSz/Idps3JcHyNK0YXKJ3qvrH1k0ur8Y 467 | fgHuY41d4QqShOZleDcJtDXj7Gh0BtLlijspiscBNt16BpkKzEcqd/6Pt1fMIOEx 468 | iBXrdad9mPpZT14KTXT8dXHtAEKozut37a4hLfJ7al+XBqilnYEm1OjVx/BVKwAR 469 | AQABiQG2BBgBCAAgFiEE6gIlYKgeW9SNs9GLVKyOLZjP6sYFAmB1tD4CGwwACgkQ 470 | VKyOLZjP6sbEogv+LX9Z8BlnClkJ3lVMZlyzbUf2lleg+QA4cWTsPE4SSi1VFHsR 471 | CAoxesJdKqJuFcIEOFxscGfpkSbhTsTEczI9e2XsaaDAaY1GodvJfRUAu2VdvVAG 472 | xHhoEqUUSbD4r3AW0yLViLlsQVoiuKIizm8PQZr9bfLSkXjGQz1wlPfZVC7raPJ1 473 | VYb3TQXmIALTc8peel2SlqFLQVZ+3Lb8JKC/9DeHAGmpBipB+VcSC5vRchqpncsH 474 | Az0GXtmqzkgcyzq0Kyh0nIshDsGQ/vXoZQRl5hjMWBLaN/y5ik7Qde4bjL7p1ozK 475 | Vm0S2qY0CfrGSzZnLXLOxX90fqXXN9cwmLv++bdyrXElA10u9LIqsViop3UvHitV 476 | jkJlIhwt9/duJEhPJnT/qH2O9YAqwlEFggSNSctD3LC1uMjB8JD6XcpQgDP6BiZU 477 | wP/yCGQGvA27Omf2WgrpGukXiZFSBkCZPL+/rcP5dnVrCwneGCXluI+sONfybagy 478 | 2nNTTJWxonBh7c5p 479 | =ksoJ 480 | -----END PGP PUBLIC KEY BLOCK----- 481 | 482 | id AD296CA014321485EB6780FF8B8E0CB0F6A7657E 483 | uid Robert Panzer 484 | -----BEGIN PGP PUBLIC KEY BLOCK----- 485 | 486 | mDMEYpEQgxYJKwYBBAHaRw8BAQdAAyUqDlsM76TEI9sgzz6DaXhdy7BqSrZ1C/Hi 487 | P8QhqbK0JFJvYmVydCBQYW56ZXIgPHJvYmVydC5wYW56ZXJAbWUuY29tPrg4BGKR 488 | EIMSCisGAQQBl1UBBQEBB0AJY1E2mT4hAuveR1BnaNwwosfF1JiwU7ihSB0aiytl 489 | DAMBCAeIfgQYFgoAJhYhBK0pbKAUMhSF62eA/4uODLD2p2V+BQJikRCDAhsMBQkD 490 | wmcAAAoJEIuODLD2p2V+VMEA/j1HUrIcDQ+FZtFsVQOnCjgIoeOzphExVVZmOjr2 491 | mAQWAPsFmTyYBbzvAHsj8KBEyO6FlSY0mKQlJxIelqBxUlxyDw== 492 | =oQqF 493 | -----END PGP PUBLIC KEY BLOCK----- 494 | 495 | id 3690C240CE51B4670D30AD1C38EE757D69184620 496 | uid Lasse Collin 497 | -----BEGIN PGP PUBLIC KEY BLOCK----- 498 | 499 | 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 604 | mBUN4AU6 605 | =kKlc 606 | -----END PGP PUBLIC KEY BLOCK----- 607 | 608 | id A31DDE881C3E3C4C985BD0D02C7F998F4272C851 609 | uid DiffPlug LLC (release signing key) 610 | -----BEGIN PGP PUBLIC KEY BLOCK----- 611 | 612 | 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 646 | UHYdDPZy0fDC7G6GiejrwZhbfcZW1GhKwvRVG+oBtHoq/w7KlFGHCAKZ6zAI20GF 647 | xqS+7gI3Bbx2eN2Hm2/qDuYg54KAGy7KKNjs4z3deu/alhPXx67PXkxyWKUMcGq4 648 | yUbwTQnvg7whI3A2ZKKzEACDO7b1a54JTxqg8RdGim+mBVLFnQNHxVlxtQEDYxRJ 649 | TcTuluFI5s5rdZ5dCMt8+cdAqyiSmDRDXt4Dc0h6EoxTyfeFiBWJe1WxyLNclLyD 650 | Aae9W+VGhxPhzQVJ7/YvCQjuJozVDaX5RSWJE490r8PKDUUK8NUdAfKP17X5urDm 651 | /YOZ7JIwvewP1yFSWpQQnS0VK3QQirTBMvNNZ90RnBDfvjs+/63EoCsagm2AInKR 652 | CQnaC/+2a2tZoXt4mqb9X1vYFlRts+xxePSPFnPuLmVB3XAMbPEoxaqRp2BvyGa5 653 | j0HjtxKbV0Z+xREGmjd7JbnBW9se/J4ij3JdcV9WRU+JJ0JNUCLBMULTMl3DIC8V 654 | sBuPt980cnI16yJLn/qMlQHiJ/r7cdg9blQxD2aiDb0qkpDDZNEBQLWGtb/7Wzd+ 655 | Wwa9fcP5QP6zw3MhTqk1JDCmAhEOsj4WtTWAtBJweMJsavnpaeOH1UtWYM36VhGk 656 | GLViJ2LzBrmdJyAlzPwktHbh+0n6kbq8ysVnxUV+aLSEVjHsQRQxD+nSV71A4WNq 657 | g2jRvph10jbVWvoy4pOSmpTH5jG9TO2SlVBETjrHMVVY5GiRliFDzvPLRV9HoVye 658 | TnPH0XeWTNKTUK9MUC3NOZHlc0HzbD/hU4oLRJILcKt7YOEmzt/p6ZGH6J7jb/NB 659 | Eg== 660 | =PrQD 661 | -----END PGP PUBLIC KEY BLOCK----- 662 | 663 | id 4797B4F5DCC46CEA61059071A1AE06236CA2BA62 664 | uid DiffPlug LLC 665 | -----BEGIN PGP PUBLIC KEY BLOCK----- 666 | 667 | xsDNBGPAYVUBDADCs9PkY8zzhzE38bRZX+vTrr3LdChGNBmObV858NGRrXeZtyLu 668 | U7YwYVF7w2vHUI/JQWrlPZc5tBFicefucfUtKt790WzAk3NBjGtX4IWpG57C1Z5t 669 | QRI23HqWr1If0UanH2vUjy4fUgNZdYlH2KzookoU0950dIcqwA/HwiosO5RmQ9iY 670 | HztkwwvFW9QxiJgL+lR84EcaIVN1ukr0ZKrG1a6wOJ6HLf9S2F3DMe7fQ+O+TpT/ 671 | A11RewOZHwE9spH8cEsNYgutBouw/MttuYHjZKD7O4hN12MmzecWeMAPyrvYgTJp 672 | PHcjQaVeD27OGLRpy5n5LonvkzJbhTzM+Ps1qEj/4of3EFVhxNjR0gdrkX+0Ub1A 673 | XXiw3gjqAQuLQVKIbwvCbfj2go+YHrfcXN6kpKkYZU8ERPxI/VBTw230PPdXXwXP 674 | Ux/JRQIEXOuMIuELm/91H8TXKutw6NdNRu5q+LPcUkU7W6jsv28dmQHdC+ebVHlA 675 | vNcBOWVSY5e8IasAEQEAAbQjRGlmZlBsdWcgTExDIDxzc2xjZXJ0QGRpZmZwbHVn 676 | LmNvbT7OwM0EY8BhVQEMAL4ZVuEVH9zbhY6AewA4T3u2XZ7k1KGOxoK74eygzYEp 677 | fKMplWQtCxcxBXe2tboT7I8U3MrV6m7KDwcxLNVZM638fvfU3Px0yGs0jBzyjOcb 678 | Vk6n18xX9UoNyoEqpxHhyPbTBr+U9OINcneXZ/iG9FfLURZjDxhNcQcnrnmvbUB6 679 | M+teZ6Gpb1Ye8ghVCJJNjRRQhFxXE7XnmX3C1pZoSoGcBx5zVspSuHjq7nTTw/rd 680 | 7OpC6sBK0ULk8GPAd2vJUfOtZcsLvOs2++bHxNULTXraTy/fYvXsTSe+PmbJo1Fd 681 | 5o3imI0eUy853UJmF/HbuWspFe8yONHjo0+uZITsAMq0jbzG8MTKMmgsXS/i/vaW 682 | 8BVUmLfhB7E+bUXJLJuQAan397NbYZqPF5agLZ1wHSki3iuYEttdMsy5PYCLeCqh 683 | 8Tv6VBNkEToKDAvNbaad4ZgBdwbBQaAIrWekWpiXSXizyGr/VTFE2hT5NC0d1BXy 684 | sc9P2UCvHit6A1bCl7MSywARAQABwsD8BBgBCAAmFiEER5e09dzEbOphBZBxoa4G 685 | I2yiumIFAmPAYVUCGwwFCQPCZwAACgkQoa4GI2yiumIHXwwAh4/tSXSQ9Btws4ZP 686 | eLfihAb4ogHOsrJ8ZO+lZMyQOrEyzDK/y/1LpFVlHYEP51XS5h4u4XVivXGzsZ+r 687 | tQoXaCS6n19dyyNeusehZx/BxxQrdV9OYEkgb3BC+05AWogdHXTP4prGdMtpSttd 688 | gcxTuHwx9RUv/d6CsQ8DyKyjTv82hd3yuXQVl1829NwDbM7HJ8eq0uZPmez2ewbx 689 | Ze9CxjKoOLfYSQ4k0DfcIFqz8CSqTVIz5aNLLXiY6NXPhS9B9/bXkRNAXzUgMrG4 690 | GmmP8XLYjBn9g8V+fAad67N0dUWDeAPzz3OXjp6bxyScgjT6OMlp55xXaE5HWW4a 691 | aE9epjKjLuOD7LYdmv0GI1HhSrOnlqznB3TCwJgKMw6/37uGZnpsX0JoMs947ZIm 692 | pcN1kNNR3e4aAFcpBwj2OSjds+G/DI3/WOXJj3aaRI4nBRr2/IB3TVhzLOizLTNQ 693 | Q/IKL5Iy5doINK/iyjb/G/JLH1/TkhW9zEheiKUY6TiXeR3p 694 | =fdmt 695 | -----END PGP PUBLIC KEY BLOCK----- 696 | 697 | id 8756C4F765C9AC3CB6B85D62379CE192D401AB61 698 | uid Bintray (by JFrog) 699 | -----BEGIN PGP PUBLIC KEY BLOCK----- 700 | 701 | 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 735 | E/XhP4QkRJrZI1F/ 736 | =Jm2n 737 | -----END PGP PUBLIC KEY BLOCK----- 738 | 739 | id 6F538074CCEBF35F28AF9B066A0975F8B1127B83 740 | uid Kotlin Release 741 | -----BEGIN PGP PUBLIC KEY BLOCK----- 742 | 743 | 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 888 | BedOSN7DqsnvIUfFaQ== 889 | =bvfg 890 | -----END PGP PUBLIC KEY BLOCK----- 891 | 892 | id DBD744ACE7ADE6AA50DD591F66B50994442D2D40 893 | uid Square Clippy 894 | -----BEGIN PGP PUBLIC KEY BLOCK----- 895 | 896 | xsFNBGDoYisBEACqUDZnT4h6ma6XIzdC6KR++uDbR2VKdhCuv0Og/sHEKkm6ZbG0 897 | OFB8tAaQx/WlsoQyf3DlLfUEOGDai875Aqor3fbM+E1hrZbQNfsOySKEE52k7PYe 898 | 0qGWlnAzINuQaEuZwNw+pjZqPraMlwc/hwzJB8yFNHCv25pCFohK7KXvFGr5Fc6y 899 | NHBp6pM3pnDQ1kbkloDr32YZY2LdrfdkRqwa9STNMcZtM724aaInValFpVGEHolF 900 | dklo9MIsMI6mVHlxi6UwFSSLltUfTXGYY+rt2Q2sLNnEKzK1GvVhK996vrNWCvpr 901 | cdtbTzGE3WK4f2knhqzlaX99OLmkM1ah+p2EkK7HgWM9oEO7SYpNxKe/F/QfRNRS 902 | 4W0aokPsEtfKCD7vQ3cRWQXdqFwvksilv+b6pcSrwfAsaCzVuhB3lcIra4MevJcH 903 | ZEbPrfGMi5/MIVtLayglLHSPoZtjQBhlqo8w3nuADR/aFlIUZ6NGOwaz5yXIGVEs 904 | 6E1wiuILRAd7ecJ3Zyr/URHjawfHfKMM2tNCJKl48cScBMY61FJ1EmYzwhDw+at5 905 | D4pCk75eM5/t6VdYQ1cDWm7J3LGXEANMU5aSZMqgVnb4SQEmRxkW7oq3Z+GIkQQf 906 | Sj4OK6Oi4cUpM7b0m7Cbcsoqb6nD27VKD3J5KTYEq3e+78h0VRjhoi0Z+QARAQAB 907 | tCdTcXVhcmUgQ2xpcHB5IDxvcGVuc291cmNlQHNxdWFyZXVwLmNvbT4= 908 | =Vcde 909 | -----END PGP PUBLIC KEY BLOCK----- 910 | 911 | id 9E3044071B758EBCB7E45673700E4F39BC05364B 912 | -----BEGIN PGP PUBLIC KEY BLOCK----- 913 | 914 | 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 982 | 2bX9MtjSsKhYeVDZhwUHbX5VuRtS+X0IIFhu1Q== 983 | =xPkk 984 | -----END PGP PUBLIC KEY BLOCK----- 985 | 986 | id 7C669810892CBD3148FA92995B05CCDE140C2876 987 | uid Matthias Sohn 988 | -----BEGIN PGP PUBLIC KEY BLOCK----- 989 | 990 | xsJuBEwVZOURCADNnKQzSjFuI9/IGj3WTJcPU2B/H8NbZaTsz5WE91WumgZulK2q 991 | YeD4u6zdOyFK7DEScgxk7dicox9cNEgYKQnQXctDhfqER9bnvA2iJ+AFxjRAWyvs 992 | en3ClYLXT5UVx0H1ZfDVKCvmaZVirZInfkqbi3OiPQoWrUfu02c3DiHQJ+Y34kdB 993 | egH2sIShNH8WLfEZ3YDQ4XaWHVuN1C7VwCBM8R3OeTTfyDrTsuyqJ0SeZXRR/6df 994 | 2pEckjF9DNSXyjzFg24MrZhuhgbnj0oR1zmRh1EF+KlBfF4DF4acfxWqqcJVJx/3 995 | FTtOkLe3Xjj+inyJgxOW52gD4DsJpyf1tIbjAQDZvOdlRRCqZB4FnzzIb/1GmkGD 996 | JpDLC4MQmqgxkm0n8wgAmmHLpqDTdmuyJXvdX9RdGycpW64sljd1mpzTWJ8UKDhj 997 | uFQVHSSEdLoHoVj8ItnBV2kXd2uoQ/tWzbxFBST7wE/tX0e9G5XWaPKogvOKeDus 998 | u9XTIds2krYp80UTYWFZ88oNwGikdIrEYURSYDsYt15miROtKHWbSOHeLVbZqgVx 999 | dtWPqQVfH4gJGEH97/OSmozqDVog1aZDKBLGZQosng5h4j2RAQpjkaIdxKl8m7CQ 1000 | x0Yi9tA8yD1QhRGggANQIb4n00G/vm7RMU/7NBvvjAQ/nAFjbsyO5oX1rBY1M6Xo 1001 | NFqIBrHSBzV9MmhS3nXU+ZjAktCRhyJ7TsoHM0OYEAf8CduM5Zzp5w02iVYkFQBB 1002 | wAoKHMpycW5LhMMMS4w7gmOfP7y04rtg6+zVe41y6bOqn/SxHCcCgnE/nhdexlzH 1003 | ElYE1H7+HpphoI5vEwS6uElF67CoO5r74Zrb6nshGEj2AoOqjbrsdQm0noBBNYAu 1004 | f9RsjU0sQQFzLW8+2xahqK3oZkLWOkSxzLtVwJbm7EGaGIYxEBjg87OnGQkAi9vv 1005 | tVPwdO3VWyvgKLuPHudLDhTpeH3AMbzKgnru1Pnh/ZpiRhPzsbuFtFPEX8PMuCyE 1006 | n4OLzUALl98kXuPjG5ww+24UsNgKMbKbu8qq/zRu7IHlpZvd730RoCWU2/i18tnY 1007 | zLQlTWF0dGhpYXMgU29obiA8bWF0dGhpYXMuc29obkBzYXAuY29tPs7BTQRMFWTl 1008 | EAgA+MQFGIhyA4Ww9g7J8ZiEltwSzRblrjM1q9anexsBIGsWH37A92rlVK1RzMVf 1009 | hj5yl+BzIBGO+zHbgycX7iB5/Fwsm+6R/2Uich6NDm1Qai9rc/jg3MS0phOAQzgx 1010 | lGKOTS2GzdbDJCBQMijDObNe+Cs5DNB/E29/nzzCTQvtRzSeplZNr+8Q8lWz6efX 1011 | mm5EeeZxN4x1YXjjzMJCHbc3yGxOjTgYQOs962yUYsg9UDRJm1OH9NKZe1m3dTRI 1012 | MUcZvL12dq/kyiHHR9V/6CkdiNw1AFMi3tvEdvX4D1k1/Qr/2ORZE4lRzgug4sKk 1013 | pgaclLnkJZ9EMczmUFTGbbkx3wADBQf/Y+2nZCJSuHiDv/+SdhQhOBapZ2hYPDvg 1014 | 29mpPqin/LwH7eFTNv/oos1wzuzGtTHHGEP5mUQLOxjwdAXsWMMjscSbCs66ytTN 1015 | 7X4O8qh+1yN7vrM6ZBL12Ix7Ku40cgkWyvTVLBXKaEGm4ElhAmSLFpu+/fJw0riR 1016 | 6rIuwHcGB4R1IJtMWcj+b1odgw9QmJ8AGpHh2WVdXspoCGnTUN4mDEswZjplkKXC 1017 | gLypU13SrHVOqhjd4caK5GNZUfWtCKtwNcJMnvgp2truMvh9BBn6widfK48hEknQ 1018 | tXzGjui+bZz2/AD7/OT/T1CqDspB8IQlBCMBn8J4U1grSrZ1wTJfHMJ+BBgRCAAm 1019 | AhsMFiEEfGaYEIksvTFI+pKZWwXM3hQMKHYFAl/Nd2UFCRlbrQAACgkQWwXM3hQM 1020 | KHY46gEAuNHWGw1PGYSAT5I8F+rvPQsmRY6K+007+Q/icme7bIYBALgkQgbrBPO/ 1021 | CkgxHBlvr2BJHjE+nRgTCN73Sqh6JSZXwmcEGBEIAA8FAkwVZOUCGwwFCQtHNQAA 1022 | CgkQWwXM3hQMKHbfCwEA0NIOfYpbPsdvmB4PBRNfhPxSqfbV4Vunni0VN+ikJ38A 1023 | /idN1fWJqGwKWv2rob4JZAG5BYdWarcWU9T+NOfq9dDA 1024 | =Ll5p 1025 | -----END PGP PUBLIC KEY BLOCK----- 1026 | 1027 | id A9789342F598AD5B1175EF357EB97D110DFADD60 1028 | uid Niall Gallagher (www.npgall.com) 1029 | -----BEGIN PGP PUBLIC KEY BLOCK----- 1030 | 1031 | xsBNBE9/RAsBCADI/pVIFcoLmbq4LCKkqeN4i5xgGKsuQsDAf/ndFkILDUA2FaPN 1032 | 7cI3EvZacWnWUA0QkkKNKpajU2OjjQlu4IyBosJht3VMtD0BJ2nL8eIDvwO6L8TS 1033 | 2RRGMnMaDUc91NnoxKs/7VlQ2ySk6Cm6lH3t8KVkwaJdU59lAH1ey9UKhYyvRQuT 1034 | htenl2R63lyyDe1ZLMAlmQXi4RcCWOO+L1emChNv0q0Fsir+7go9ZNYUi6pmIEva 1035 | jKXM8bo/VtRIHrS73DsH7BVVCURYoBWexZWlRdb86KSE993dRXLvFPy5JzlRM+eu 1036 | mUY3CMKxx3nLaDN5qepf1nGzMW88xjq4z4rhABEBAAG0M05pYWxsIEdhbGxhZ2hl 1037 | ciAod3d3Lm5wZ2FsbC5jb20pIDxuaWFsbEBucGdhbGwuY29tPs7ATQRPf0QLAQgA 1038 | 68HLImPvBSPnMtjUHczE+gccsVWzLEsjVYSBcOUi1j67KQHbTPcHAqzYJl19t4FA 1039 | N/yU1oOjuu/4GKVni27y8NGSavzY5elTZ22lqUqgqT6DjoOG2BTLHuOiNRIMqBmD 1040 | Gy41mEq62C9I107pqJnnbARmde4646kDiaf2vkF1BsnBx0Dp93re2eJq4rkAf803 1041 | fDvA8iyk5uDFiGg3f70JAu7ZCAKczglD0WUjIiO5Jxncz2sWiO2OuVgdsTuZf+9T 1042 | 0aODKua60Z7CLn4ZK4ZpdibbOEp66XLeaGuy5HPInTTsr4UnT2kvor/AmmPKOryp 1043 | 9oBFnPvf5+wREwlQN2h/PwARAQABwsGbBBgBAgAPBQJPf0QLAhsuBQkHhh+AAUAJ 1044 | EH65fREN+t1gwF0gBBkBAgAGBQJPf0QLAAoJENwLfphr1zmPJtcH/RJ5ba5m0Obq 1045 | BGbcJpJwhEjpB6tCOufdzvvJGAMMAuH0Vs5kXrASIJPyVgJ2ab4txg6U3DKIfxnE 1046 | IGjfdH9okl/oHRYrI/EDMN0PnIkE1JidhVOEOj3UWaoLUS8vvobKq0XP8B6J+P4q 1047 | NA5L3cPlBBtH7yqzVNavi6ljJcsJH3g7L5vJDQyw+xxfOvQq66y4lcO8ptAqB+nw 1048 | oHfSsfRKQQgT+Xlp4lG+acf+Kc0bLjWWUnBRgJfkhbGPVYHQ/QfnxbuLvlqohive 1049 | HEV+d/PxCwUHq4EtLC9d8V3ADCZgb3v9YE03abItwg7tnQBd/LuJ4qdOEbjAWI4c 1050 | crfZTmD74BkWIQSpeJNC9ZitWxF17zV+uX0RDfrdYGx7CACw7LqreqNnAHAONQdz 1051 | j4yr1nBp6Fngtq70SPKs49nDWRIJZzutzGVNs9r7bFSu/fzZlzsqi8gyYSizhEnW 1052 | BoV9e+t4YrMI6uWwDiSddzCn2fLCNkfYd36nuX78QHZgD32syCVeX/k1+zmTYjVt 1053 | Op85vZ45d17mnwCSHV7G+4jImZF/+lF5ED/x1coIT+ob4pmQk6Hwf2AP/ydfyf/l 1054 | B+boV/SIUXeZ0Esz1B0Frfr+qjAFhDO7blgUfQ0qLOIXRjavSl3g1CGgCKsZ1qZU 1055 | 99YrO8eFnxdaGSWvVV77df02pkg5xdDHWusPcEvovBUm0dx9DG5PchEOeOdhdkBQ 1056 | 5UCV 1057 | =MD5j 1058 | -----END PGP PUBLIC KEY BLOCK----- 1059 | 1060 | id 2E3A1AFFE42B5F53AF19F780BCF4173966770193 1061 | uid IntelliJ IDEA Sign Key 1062 | -----BEGIN PGP PUBLIC KEY BLOCK----- 1063 | 1064 | mQENBFKneXIBCACtnX3ZQmPujf6ocvdnhsBheze71DSl34TfebyW2Qt+g9NhMxo4 1065 | DaJy+iFNnsaMwLZRr6k/qf+ISE3A4opWAQlbk+Wb5s6DPPA2cHH6W4GdkxtuJzqt 1066 | tFn6YtkFhA15Aahr/vz31NBjUJlBmO4PwvkyxiF/MYP6TQ/AHar4xP1RxSYEPcCi 1067 | dIQczQ8nXzya4OqOyTfibeGz/eiHHuwTLHi3Rd2kihQnlRQdhE1rmm8uTyzFe1H+ 1068 | P7WW7kQgygW6yxQ3J+DXrG8kG+nbe57ZY1oyv3F/fOBxzn/kuoKHZ3JJEMJmTIrT 1069 | Lr1ngCZApgteAynRHk4t/SYZiyoyqZCuBcwHABEBAAG0RUludGVsbGlKIElERUEg 1070 | U2lnbiBLZXkgPGludGVsbGlqLWlkZWEtc2lnbi1rZXktbm9yZXBseUBqZXRicmFp 1071 | bnMuY29tPrkBDQRSp3lyAQgAvc8Q7O0gVSJsHoVgSQ5tWGwNsKcfD3I7kwC8BYHr 1072 | Q6F/UnhP1ArreNnn8KKpwOvD65pv0j5G7P9KAbIVLRRcCTB9MgJR2FPmRTNmYbKi 1073 | Pa6X6IUM/25R0SBKDJddqSvEFsE/M1ozHz4bIhdFUXJFMfv7WBaA9Cx03WwZg6Bn 1074 | 5/xMzMC/qzG7QlXOMpcABtd2JlPImH13qHWNLkhyKW7y9HCfdBz9nOy0FGT54ttv 1075 | r3BL1gahSXNi8MHP7m2I3C8dSuIpzrNVPgR2eByvSYpZN28P4Cy9l99TRcr6/FuA 1076 | y5FaL/nWpv5WAraAV4Cx5Xpr4PXTn27b7k+feH8W/+9EAQARAQABiQElBBgBAgAP 1077 | BQJSp3lyAhsMBQkSzAMAAAoJELz0FzlmdwGTSqAIAJ0/yTJRlWp+dwDZGxAffw0V 1078 | iEHPkwAQ4iEKburA8LpcbTwJRl+k9d1RvFkZSWITq+F+Putlu9QooeVwcM+ht1Mm 1079 | oah/aO3Yx+yMnXwljR7FJa5VOY2aoALeCyIx8QYiqNAVaid+bQ53gC924u5zRM+T 1080 | J+vSChtqSBi+EOOTt5C+ALVB8qWTqEcD84AVbvvippCzKsA2sV69FrsIFAShvpXo 1081 | 3xpXW83GCXxrp8nM9M0E46Y/SarvGTqfKRC6phNUXKp9c3SnVttPEcGhb9+92LOL 1082 | vMxKy4GRZS18bXDI3vS6gRDNJDCqBYIhp13Os9k+ZpnwK3PPIHv4l1I0i0EHZKk= 1083 | =WJEa 1084 | -----END PGP PUBLIC KEY BLOCK----- 1085 | 1086 | id 1D2C7EF8ADA0F794B58C7C63436902AF59EDF60E 1087 | uid Sebastian Sampaoli 1088 | -----BEGIN PGP PUBLIC KEY BLOCK----- 1089 | 1090 | xjMEY4fp+xYJKwYBBAHaRw8BAQdArb04PVwQKvEhtUEmEu7/aASZivOWgEkZBqX0 1091 | Tovwvq+0J1NlYmFzdGlhbiBTYW1wYW9saSA8c3NhbXBhb2xpQGVxdW8uZGV2Ps44 1092 | BGOH6fsSCisGAQQBl1UBBQEBB0CSPWzZfBjKWyPW+D6RDRLFz5xlO9/30yGD/VhA 1093 | EPXybAMBCAfCfQQYFgoAJhYhBB0sfvitoPeUtYx8Y0NpAq9Z7fYOBQJjh+n7AhsM 1094 | BQkDwmcAAAoJEENpAq9Z7fYOTMMBAKfZb2ahnfGNBt8Hrbu1j99580a2IaFQddAk 1095 | xXZy2unHAPYyfxDLPkbTR7Mm4k8Cva8PCcXotDow4bDLm9rhwVkJwn0EGBYKACYW 1096 | IQQdLH74raD3lLWMfGNDaQKvWe32DgUCY4fp+wIbDAUJA8JnAAAKCRBDaQKvWe32 1097 | DkzDAQCn2W9moZ3xjQbfB627tY/fefNGtiGhUHXQJMV2ctrpxwD2Mn8Qyz5G00ez 1098 | JuJPAr2vDwnF6LQ6MOGwy5va4cFZCQ== 1099 | =VAP1 1100 | -----END PGP PUBLIC KEY BLOCK----- 1101 | 1102 | id E88BF2559874BA889D34357C0555B3BA1CA4ECF9 1103 | uid Andrea Peruffo 1104 | -----BEGIN PGP PUBLIC KEY BLOCK----- 1105 | 1106 | xsBNBFeI2igBCADSyC1+7+GrBt5easeGer72OC8yrqjO/Wv6o7AYWbs3f6SRmzEi 1107 | myc1sh8gBt1NbpkhIDuxdlqSOiYU4uHn246FuEEOPFyp3SHnTkEcI3J/5JzRLpKB 1108 | p6qdA2uXSPFtyMZWiMJS84eEeuzgs2J22ankAIRhC4HsV2TWkKEE5r0TnKBAP1pW 1109 | p16sXlDaUNf5JXIVOjILwFx22hVc/ZEx/3i/MmY02ZbZTDYDHvDC/v8zyv8aXIft 1110 | aKJEuV3H+jHZXbum2KMVVKokptVAr1boq6vTth0MfHDMibBHkm0bYNTSV5dUEoQO 1111 | ZlDSAKhjJlZHRzqy3Yp6hZyOA0ELYSI31HJNABEBAAG0LUFuZHJlYSBQZXJ1ZmZv 1112 | IDxhbmRyZWEucGVydWZmbzE5ODJAZ21haWwuY29tPg== 1113 | =b3AU 1114 | -----END PGP PUBLIC KEY BLOCK----- 1115 | 1116 | id A7892505CF1A58076453E52D7999BEFBA1039E8B 1117 | uid Rafael Winterhalter 1118 | -----BEGIN PGP PUBLIC KEY BLOCK----- 1119 | 1120 | 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 1188 | pIXjPlQ0i6kV0h8KapE1Uo005JYgeg== 1189 | =/SKc 1190 | -----END PGP PUBLIC KEY BLOCK----- 1191 | 1192 | id BE685132AFD2740D9095F9040CC0B712FEE75827 1193 | uid AssertJ 1194 | -----BEGIN PGP PUBLIC KEY BLOCK----- 1195 | 1196 | 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 1228 | sMY= 1229 | =vnKw 1230 | -----END PGP PUBLIC KEY BLOCK----- 1231 | 1232 | id 28118C070CB22A0175A2E8D43D12CA2AC19F3181 1233 | uid Tatu Saloranta (cowtowncoder) 1234 | -----BEGIN PGP PUBLIC KEY BLOCK----- 1235 | 1236 | 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 1271 | 96Um/Inf 1272 | =Evfn 1273 | -----END PGP PUBLIC KEY BLOCK----- 1274 | 1275 | id 1D9866E375A1435ACE0BE0ADE3461D2D16725F94 1276 | uid Open Source 1277 | -----BEGIN PGP PUBLIC KEY BLOCK----- 1278 | 1279 | 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 1314 | =rjU5 1315 | -----END PGP PUBLIC KEY BLOCK----- 1316 | 1317 | id BDB5FA4FE719D787FB3D3197F6D4A1D411E9D1AE 1318 | uid Christopher Povirk 1319 | -----BEGIN PGP PUBLIC KEY BLOCK----- 1320 | 1321 | mQENBE89LqsBCAC/C7QToaRF8eZgGOxcvp9aG+mFFCMjaRAb4Mh59OYdmUb6ZjfO 1322 | 9388HPebGbPNR8SHYs0dBIuWY4ZJ7oUTYPswasL8vB0iPFdyHhvkCca+yk0b8ZBM 1323 | DmFlISm9HkYpoVjcFUp1oivyeJ5LRTJTd5JGEd/SWFRbB4TimdKXBzej9fIm2zVl 1324 | KInEMMd8HnSYE6nm3aNkbyiqhx81bFvl8x6X3ZMWcKs+TAVXdP9uLVvWowUwcApk 1325 | xpee442Ld1QfzMqdDnA6bGrp8LN8PZF9AXQ9Z6LTQL3p9PIq/6LPueQjpJWM+2j8 1326 | BfhbW/F2kyHRwVNkjaa68A544shgxJcrxWzJABEBAAG0J0NocmlzdG9waGVyIFBv 1327 | dmlyayA8Y3Bvdmlya0Bnb29nbGUuY29tPrkBDQRPPS6rAQgAuYRnTE225fVwuw1T 1328 | POrQdXPAOLDkiq49bLfcxwRJe+RozKrJC1iKxb751jTozEEJLe5Xj7WcojqgDsuT 1329 | jzaLHDNvDCzRFvwfkJ4scMTAZd+2GYsC8N3Gg0JRgC2lU4wZxsanLnVMbdX2L0lZ 1330 | 7WnH6S+GJ5f0Et8PM/g+V2Gj2UraBhGGak8OBQ6NhmCJBcyYg8Bh90cgD9V1hMRM 1331 | LSW7gB1vnpLM7C8Yymd3etdZSIltmDuVb3uG9s4Uwq51s2MEKsXsuFYCHTz0xT2u 1332 | +6e7Puaq5V0218QGR1Wupkl29iIUF57hFR7f6oYKkecvPKc4Yev6Ii0Mbvc1H19k 1333 | LOXUrwARAQABiQEfBBgBAgAJBQJPPS6rAhsMAAoJEPbUodQR6dGunSQH/A+4/Zbr 1334 | 2jB46q1JEN/UV4U3MBQiNvCOSD9tOPMnBvVzJ53HutvGGkmafbtbwDZaN+YMs6fi 1335 | itBMqjF/eQ/pJ54aFguTPGMFrlFyjz2n/pffkHLpVHgs8V5M4ALITttwCOo8Vv7u 1336 | 3VjO+ea5kiCm9MqJySrUP2Dv4lPVB32eoEUqWDxoyeACihW+Utdo8TBDVd+R8w36 1337 | W3CUSvujW2z9jMNTF+VoVWDQWc3up7Nqb+ztW9wrjqs73nJCv9bLPahUPNzfh742 1338 | v9vak3TkwMcDR1eZv+KvA8GXSZM6ACALzTmqRHXjGF3UZ4vowQDfiTzZKr87eBaE 1339 | FoHco7Lnn+W+8qk= 1340 | =9+x+ 1341 | -----END PGP PUBLIC KEY BLOCK----- 1342 | 1343 | id 3448B9AECE73A41DC11FEE9ADDF3944950267CD1 1344 | uid Jean-Baptiste Giraudeau 1345 | -----BEGIN PGP PUBLIC KEY BLOCK----- 1346 | 1347 | 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 1382 | =Q1Om 1383 | -----END PGP PUBLIC KEY BLOCK----- 1384 | 1385 | id 648190996EC0930A6D7D49A978178478013521D0 1386 | uid Ktfmt Team 1387 | -----BEGIN PGP PUBLIC KEY BLOCK----- 1388 | 1389 | xsBNBF6RvwcBCADIVU7oxOiljoWxNTkZ00PKVwyqhahYpN/4lamULtECCS+HAF+J 1390 | DsNy/6QCl7lKAGrSyn9dvsI56KEkGvUJfpQrpRlg+uIQDMxS8JF7p9n49DNc8Q88 1391 | XuCaiv7pv9hhCN3Mn5qcuzTR2gGP7ToZ4fQW9W/PSJBSOeO6JK6xXNyiKcyEoXp/ 1392 | jGSRqqbDkAT4OYEUy9RfG9BeJEGUbDK4RIaH5Bo0bdahq3mfdlKYXMwRWGV9D3KN 1393 | 4iLE/26h3y6tQZS5zHQGjIIJedaKGWEiMsF+b7Jjf5OEC//FoH1IS7nDz2GK9BjW 1394 | iELtSnmyDIDiFAvMY0pGsn8AQFn4JxEP3TMTABEBAAG0GUt0Zm10IFRlYW0gPGt0 1395 | Zm10QGZiLmNvbT7OwE0EXpG/BwEIAPuROTIEOMOtp07cZ0bYwuPEsX40TJNFPOxg 1396 | ak9Mx9RSfzhSNnQ0HaxaGc7O+HelsE6xeWtivbuHWjveWUvoxvkjaoYQ9WVtDN/s 1397 | Bh2kwxS26BkvlxbbA25ZDgjk+M0xCqwkB0WX2O5PoV17+KJUhrxU9ySKe4ROCTnT 1398 | zLIgfTvlaL1nzsJd/NWDN5RhzBKe9Uv9pcxZAmZySDXmn6z62B55TXyeyvzQZWaH 1399 | acHb4DYdCE7tPkfVY+7kV+LvaLOsWsBf5v+Eo4yQb1EFc4Yd/jgMTq8GUAnN8isS 1400 | HeQ14Sb1r3mHSPA+/8Q/SGZ5s+NJc13/RS2Q8OhiOE007JO2nDEAEQEAAcLAfAQY 1401 | AQgAJhYhBGSBkJluwJMKbX1JqXgXhHgBNSHQBQJekb8HAhsMBQkDwmcAAAoJEHgX 1402 | hHgBNSHQXSsH/jmg51oPLs8Qu0USx4aHVgmD0F3//9xssxx3/SW5l6iR8UPKoxUy 1403 | 2uUOAZ8xSrDa8arNxfrSf1h5WRrJ0GqiKMJm8eeVDuLaFnGYX1LuMgC2qCrfNlQ0 1404 | 9DdFEHYHnxyEoyjBPWgqcZpa/bYMTiOjbHz+HEQs7gUBGEEuWh2zezp5MX6a50zB 1405 | D7whEN9qwzVz1fxdAwb5Xl+iXqQZ+mYvQo+TBqbM/KNcDb3a6hv904Fcdzy0Seb3 1406 | aXWb3uzaQDSJEEJxxEgWjUG9uEuS+eMD4TJqrsfg6TqN6ykXvdbXTHO2cD0DFFZN 1407 | zO5quWpqxTLMSgNswFB4mjvd0mS3bUK4DhM= 1408 | =3R74 1409 | -----END PGP PUBLIC KEY BLOCK----- 1410 | 1411 | id EE0CA873074092F806F59B65D364ABAA39A47320 1412 | uid Liam Miller-Cushon (Error Prone releases) 1413 | -----BEGIN PGP PUBLIC KEY BLOCK----- 1414 | 1415 | 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 1450 | xquhnpl2HvE= 1451 | =A/Aj 1452 | -----END PGP PUBLIC KEY BLOCK----- 1453 | 1454 | id 78DA3333F653B1C54A938BE24DB7BC57DFDBCEA4 1455 | uid Timothy Wall 1456 | -----BEGIN PGP PUBLIC KEY BLOCK----- 1457 | 1458 | xsBNBFBm+zUBCACsrBpO6mOsZ/B6PdPPV/Hj87m2GHeEYEHt2o2l8X2BdbZKbVW1 1459 | FIKnpYe3+TsFCe/qNxlR6vk0Jpy3ChD3nW/J0rmU0ju1SZnS7rdSMj3AI5M5xxpy 1460 | Vn03vCbYyFWw4Bj9avYmiz8kC7yImfGfTLv5XPmlHhUQaxW8+s+393n1mHZsIZTt 1461 | +luPftSLCkcmKGHn+PUkFaHHD+q+TTaG98nDkkaCXS0JwXzujYDJDQgV+6HB6PO3 1462 | gJJW4QcUHWa5uUY4CfqGcYGBvzlfII2psyKFIHqrx1uHxbhjLlIwif6I+Q9OFcdq 1463 | qq4JgVnWti2dEBgOVunb5S0KnN40VcH0v3VVABEBAAG0IVRpbW90aHkgV2FsbCA8 1464 | dHdhbGxAdXNlcnMuc2YubmV0Ps7ATQRQZvs1AQgAumH3wbBy7RYBaRjaWjN90OKc 1465 | pXuJ0MTIzkgC/JtNexIVtzFdrfmHPOEZESYyLVk0E5YU5i3ux+K9ARi+bWrst3s1 1466 | iiPfebeNCRU0lmxI7fih/r+PxcTTdJnHAoZUNBK1ZzjlTgXacradjS1LGFX5+52g 1467 | TgFVNlYXvI3qPKQFb+Vfz3x4LwOI10ipnqZK61D/FC96JD0osEFJkmFvI5n00Vww 1468 | XXRoeefN44Guvs58nf6MNi9ZA11iQlK2a8CswAuHJTndkQejVq5D1+ejVVmt27mH 1469 | 5RhG1xoNZ6FSkha+Y3ImTpxQMJzdbkOtMzj1S2VIt8ZcrV/6dt+yCAskTFW/ewAR 1470 | AQABwsBfBBgBAgAJBQJQZvs1AhsMAAoJEE23vFff286kd/gH/2Wz5zWkcvk8ReH1 1471 | Ke9vYH2gee0qtXIrCjtV1WBOTy0NLm0S4Bx/uFjbFUbqNK0nKjTix4mAe9KrVJwN 1472 | 47mXVGxG5N79KkiS8lj+YM8WOUIe5tkDovzEfqFukzgpHBY3CXjiojugxVv6cEe1 1473 | GLnEEOYJlezZj02HS0D1eEeIdu7aV6f6xPFAo2q94aavz8cC01IXrnccUfuDtBJE 1474 | VqdZmVoc/5tUZf/dU2m5ga62U7yaVbiimP2NXIL2tzGLgyUaT73E3e+EXzfcpJaO 1475 | rBqbcs+2HPfAjBm/km/0EC3ET0r2Vqoq40hP3fQqLSC/LYK6Vbuc/l5M0I1QxhJ1 1476 | njCEin0= 1477 | =U1nj 1478 | -----END PGP PUBLIC KEY BLOCK----- 1479 | 1480 | id C7C5042998FCB6E396E8D262BA19949FA2609216 1481 | uid TestLens Team 1482 | -----BEGIN PGP PUBLIC KEY BLOCK----- 1483 | 1484 | xjMEaC2deRYJKwYBBAHaRw8BAQdAvJBFwHDd7oAr3s1s48XDfmzn7ykWEWwsbSz2 1485 | 99TDnEXNIVRlc3RMZW5zIFRlYW0gPHRlYW1AdGVzdGxlbnMuYXBwPsKTBBMWCgA7 1486 | AhsDBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAFiEEx8UEKZj8tuOW6NJiuhmU 1487 | n6JgkhYFAmgtnjwACgkQuhmUn6Jgkhah+wD9FICp4PiH3W/xGE8PLE+UjY3zOZ9h 1488 | pKoKk0URoL9jHS0A/2YMgcceoufzcWZMzImDx7/1sqx2YQayYBAkpksVZt8CzjgE 1489 | aC2deRIKKwYBBAGXVQEFAQEHQGGJvgccps60/0wqB2PCLnMW7640+ApjxvXl6vot 1490 | lyRQAwEIB8J4BBgWCgAgAhsMFiEEx8UEKZj8tuOW6NJiuhmUn6JgkhYFAmgtnnEA 1491 | CgkQuhmUn6JgkhZmBQEA3b5QhIg4LhToSGJ0sI3mPr270z+Sefyl/L8s2i7ZJKEA 1492 | /1su4aPLl+FaeuZHpInOy991PXFh+IJICL1irc2DfV4G 1493 | =stfL 1494 | -----END PGP PUBLIC KEY BLOCK----- 1495 | --------------------------------------------------------------------------------