reqorked Gradle 8 compatibility adding a task to extract envelope launcher

This commit is contained in:
2023-03-04 20:53:37 +08:00
parent 0ea990f8e8
commit 54bf96c29a
4 changed files with 74 additions and 43 deletions

View File

@@ -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<ExtractLauncherTask> extractLauncherTaskProvider;
@Getter(onMethod_ = {@Input, @Optional})
private final Property<String> 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

View File

@@ -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<Project> {
@Override
public void apply(Project project) {
BasePluginExtension basePluginExtension = project.getExtensions().getByType(BasePluginExtension.class);
Provider<EnvelopeJarTask> envelopeJarTaskProvider = project.getTasks().register("envelopeJar", EnvelopeJarTask.class, t -> {
t.setGroup(BasePlugin.BUILD_GROUP);
t.setDescription("Package the application in a single executable jar file");

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}