From 54bf96c29aca0bafb51da4d3b4678d1a328e50ab Mon Sep 17 00:00:00 2001 From: Walter Oggioni Date: Sat, 4 Mar 2023 20:53:37 +0800 Subject: [PATCH] reqorked Gradle 8 compatibility adding a task to extract envelope launcher --- .../gradle/envelope/EnvelopeJarTask.java | 55 +++++-------------- .../gradle/envelope/EnvelopePlugin.java | 2 - .../gradle/envelope/ExtractLauncherTask.java | 38 +++++++++++++ .../gradle/envelope/LauncherResource.java | 22 +++++++- 4 files changed, 74 insertions(+), 43 deletions(-) create mode 100644 src/main/java/net/woggioni/gradle/envelope/ExtractLauncherTask.java diff --git a/src/main/java/net/woggioni/gradle/envelope/EnvelopeJarTask.java b/src/main/java/net/woggioni/gradle/envelope/EnvelopeJarTask.java index 5124486..ebdb856 100644 --- a/src/main/java/net/woggioni/gradle/envelope/EnvelopeJarTask.java +++ b/src/main/java/net/woggioni/gradle/envelope/EnvelopeJarTask.java @@ -10,6 +10,7 @@ import net.woggioni.envelope.Common; import net.woggioni.envelope.Constants; import org.gradle.api.Action; import org.gradle.api.GradleException; +import org.gradle.api.Project; import org.gradle.api.internal.file.CopyActionProcessingStreamAction; import org.gradle.api.internal.file.FileResolver; import org.gradle.api.internal.file.copy.CopyAction; @@ -23,6 +24,7 @@ import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.TaskContainer; import org.gradle.api.tasks.WorkResult; import org.gradle.api.tasks.bundling.AbstractArchiveTask; import org.gradle.internal.Cast; @@ -31,16 +33,12 @@ import org.gradle.util.GradleVersion; import javax.annotation.Nonnull; import javax.inject.Inject; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; -import java.security.DigestInputStream; import java.security.DigestOutputStream; import java.security.MessageDigest; import java.util.ArrayList; -import java.util.Arrays; import java.util.Base64; import java.util.Collections; import java.util.Iterator; @@ -66,6 +64,7 @@ import static java.util.zip.Deflater.NO_COMPRESSION; public class EnvelopeJarTask extends AbstractArchiveTask { private static final String MINIMUM_GRADLE_VERSION = "6.0"; + private static final String EXTRACT_LAUNCHER_TASK_NAME = "extractEnvelopeLauncher"; static { if (GradleVersion.current().compareTo(GradleVersion.version(MINIMUM_GRADLE_VERSION)) < 0) { @@ -74,6 +73,8 @@ public class EnvelopeJarTask extends AbstractArchiveTask { } } + private final Provider extractLauncherTaskProvider; + @Getter(onMethod_ = {@Input, @Optional}) private final Property mainClass; @@ -134,6 +135,15 @@ public class EnvelopeJarTask extends AbstractArchiveTask { @Inject public EnvelopeJarTask(ObjectFactory objects, FileResolver fileResolver) { + Project rootProject = getProject().getRootProject(); + TaskContainer rootProjectTasks = rootProject.getTasks(); + if(rootProjectTasks.getNames().contains(EXTRACT_LAUNCHER_TASK_NAME)) { + extractLauncherTaskProvider = rootProjectTasks.named(EXTRACT_LAUNCHER_TASK_NAME, ExtractLauncherTask.class); + } else { + extractLauncherTaskProvider = rootProject.getTasks().register(EXTRACT_LAUNCHER_TASK_NAME, ExtractLauncherTask.class); + } + getInputs().files(extractLauncherTaskProvider); + setGroup("build"); setDescription("Creates an executable jar file, embedding all of its runtime dependencies"); BasePluginExtension basePluginExtension = getProject().getExtensions().getByType(BasePluginExtension.class); @@ -151,42 +161,7 @@ public class EnvelopeJarTask extends AbstractArchiveTask { mainClass.convention(javaApplication.getMainClass()); mainModule.convention(javaApplication.getMainModule()); } - File launcherFile = new File(getTemporaryDir(), "launcher.jar"); - updateLauncherFile(launcherFile); - from(getProject().tarTree(launcherFile), copySpec -> exclude(JarFile.MANIFEST_NAME)); - } - - @SneakyThrows - private void updateLauncherFile(File launcherFile) { - byte[] buffer = new byte[0x10000]; - boolean launcherFileToBeWritten; - if(launcherFile.exists()) { - MessageDigest md = MessageDigest.getInstance("MD5"); - try (InputStream inputStream = new DigestInputStream(LauncherResource.instance.read(), md)) { - Common.write2Stream(inputStream, new NullOutputStream(), buffer); - } - byte[] sourceDigest = md.digest(); - md.reset(); - try (InputStream inputStream = new DigestInputStream(new FileInputStream(launcherFile), md)) { - Common.write2Stream(inputStream, new NullOutputStream(), buffer); - } - byte[] destinationDigest = md.digest(); - launcherFileToBeWritten = !Arrays.equals(sourceDigest, destinationDigest); - } else { - launcherFileToBeWritten = true; - } - if(launcherFileToBeWritten) { - try (InputStream inputStream = LauncherResource.instance.read()) { - try (OutputStream outputStream = new FileOutputStream(launcherFile)) { - Common.write2Stream(inputStream, outputStream, buffer); - } - } - } - } - - @Input - public String getLauncherArchiveHash() { - return Common.bytesToHex(Common.computeSHA256Digest(LauncherResource.instance::read)); + from(getProject().tarTree(extractLauncherTaskProvider.map(ExtractLauncherTask::getLauncherTar)), copySpec -> exclude(JarFile.MANIFEST_NAME)); } @RequiredArgsConstructor diff --git a/src/main/java/net/woggioni/gradle/envelope/EnvelopePlugin.java b/src/main/java/net/woggioni/gradle/envelope/EnvelopePlugin.java index 6a936cb..86f1589 100644 --- a/src/main/java/net/woggioni/gradle/envelope/EnvelopePlugin.java +++ b/src/main/java/net/woggioni/gradle/envelope/EnvelopePlugin.java @@ -4,7 +4,6 @@ import org.gradle.api.DefaultTask; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.plugins.BasePlugin; -import org.gradle.api.plugins.BasePluginExtension; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.JavaExec; @@ -13,7 +12,6 @@ import org.gradle.api.tasks.bundling.Jar; public class EnvelopePlugin implements Plugin { @Override public void apply(Project project) { - BasePluginExtension basePluginExtension = project.getExtensions().getByType(BasePluginExtension.class); Provider envelopeJarTaskProvider = project.getTasks().register("envelopeJar", EnvelopeJarTask.class, t -> { t.setGroup(BasePlugin.BUILD_GROUP); t.setDescription("Package the application in a single executable jar file"); diff --git a/src/main/java/net/woggioni/gradle/envelope/ExtractLauncherTask.java b/src/main/java/net/woggioni/gradle/envelope/ExtractLauncherTask.java new file mode 100644 index 0000000..27dffb0 --- /dev/null +++ b/src/main/java/net/woggioni/gradle/envelope/ExtractLauncherTask.java @@ -0,0 +1,38 @@ +package net.woggioni.gradle.envelope; + +import lombok.Getter; +import lombok.SneakyThrows; +import net.woggioni.envelope.Common; +import org.gradle.api.DefaultTask; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.TaskAction; + +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +public class ExtractLauncherTask extends DefaultTask { + + @Getter(onMethod_ = @OutputFile) + private final Path launcherTar; + + @Input + public byte[] getInputHash() { + return LauncherResource.instance.getHash(); + } + public ExtractLauncherTask() { + Path tmpDir = getTemporaryDir().toPath(); + launcherTar = tmpDir.resolve("launcher.tar"); + } + + @TaskAction + @SneakyThrows + public void run() { + try(InputStream inputStream = LauncherResource.instance.read(); + OutputStream outputStream = Files.newOutputStream(launcherTar)) { + Common.write2Stream(inputStream, outputStream); + } + } +} diff --git a/src/main/java/net/woggioni/gradle/envelope/LauncherResource.java b/src/main/java/net/woggioni/gradle/envelope/LauncherResource.java index cfc6808..989edc5 100644 --- a/src/main/java/net/woggioni/gradle/envelope/LauncherResource.java +++ b/src/main/java/net/woggioni/gradle/envelope/LauncherResource.java @@ -3,18 +3,25 @@ package net.woggioni.gradle.envelope; import java.io.InputStream; import java.net.URI; import java.net.URL; +import java.security.DigestInputStream; +import java.security.MessageDigest; import javax.annotation.Nonnull; + +import lombok.Getter; import lombok.SneakyThrows; import org.gradle.api.resources.ReadableResource; import org.gradle.api.resources.ResourceException; final class LauncherResource implements ReadableResource { - static final ReadableResource instance = new LauncherResource(); + static final LauncherResource instance = new LauncherResource(); private final URL url; + @Getter + private final byte[] hash; private LauncherResource() { url = getClass().getResource(String.format("/LIB-INF/%s", getDisplayName())); + hash = computeHash(); } @Override @@ -39,4 +46,17 @@ final class LauncherResource implements ReadableResource { public String getBaseName() { return "launcher"; } + + @SneakyThrows + private byte[] computeHash() { + MessageDigest md = MessageDigest.getInstance("MD5"); + try(InputStream inputStream = new DigestInputStream(read(), md)) { + byte[] buffer = new byte[0x10000]; + while(true) { + int read = inputStream.read(buffer); + if(read < 0) break; + } + } + return md.digest(); + } } \ No newline at end of file