From bd0d24389d35194f9bd2f8ec36915c5288b46b7e Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:50:02 -0800 Subject: [PATCH 1/7] Cache applied/extracted classpath from Paperclips instead of Paperclips themselves This means the Paperclip does not need to be setup for each project using it, saving on overall disk space --- .../xyz/jpenilla/runpaper/task/RunServer.kt | 10 ++ .../runtask/service/DownloadsAPIService.kt | 8 +- .../service/DownloadsAPIServiceImpl.kt | 110 +++++++++++++---- .../xyz/jpenilla/runtask/task/AbstractRun.kt | 23 +++- .../xyz/jpenilla/runtask/util/extensions.kt | 7 ++ .../kotlin/xyz/jpenilla/runtask/util/files.kt | 12 ++ .../xyz/jpenilla/runtask/util/paperclip.kt | 111 ++++++++++++++++++ tester/build.gradle.kts | 43 +++++-- 8 files changed, 284 insertions(+), 40 deletions(-) create mode 100644 plugin/src/main/kotlin/xyz/jpenilla/runtask/util/paperclip.kt diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runpaper/task/RunServer.kt b/plugin/src/main/kotlin/xyz/jpenilla/runpaper/task/RunServer.kt index a4e8a65..29d0d52 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runpaper/task/RunServer.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runpaper/task/RunServer.kt @@ -26,6 +26,7 @@ import xyz.jpenilla.runtask.pluginsapi.PluginDownloadService import xyz.jpenilla.runtask.service.DownloadsAPIService import xyz.jpenilla.runtask.task.RunWithPlugins import xyz.jpenilla.runtask.util.FileCopyingPluginHandler +import xyz.jpenilla.runtask.util.spec import java.io.File import java.nio.file.Path @@ -63,6 +64,15 @@ public abstract class RunServer : RunWithPlugins() { displayName.convention("Paper") } + override fun resolveBuild(): List { + val result = super.resolveBuild() + if (result.size != 1) { + // Default main class to CB main when the applied Paperclip classpath is resolved to multiple files + spec().mainClass.set(mainClass.orElse("org.bukkit.craftbukkit.Main")) + } + return result + } + override fun preExec(workingDir: Path) { super.preExec(workingDir) diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIService.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIService.kt index 9f2d33c..f6a1055 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIService.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIService.kt @@ -19,7 +19,10 @@ package xyz.jpenilla.runtask.service import org.gradle.api.Action import org.gradle.api.Project import org.gradle.api.provider.Provider +import org.gradle.api.provider.ProviderFactory +import org.gradle.jvm.toolchain.JavaLauncher import org.gradle.kotlin.dsl.registerIfAbsent +import org.gradle.process.ExecOperations import xyz.jpenilla.runtask.paperapi.DownloadsAPI import xyz.jpenilla.runtask.paperapi.Projects import xyz.jpenilla.runtask.util.Constants @@ -44,9 +47,12 @@ public interface DownloadsAPIService { */ public fun resolveBuild( project: Project, + providers: ProviderFactory, + javaLauncher: JavaLauncher, + execOperations: ExecOperations, version: String, build: Build - ): Path + ): List public companion object { /** diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt index d5ce5b6..be904ad 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt @@ -26,18 +26,24 @@ import org.gradle.api.file.DirectoryProperty import org.gradle.api.logging.Logger import org.gradle.api.logging.Logging import org.gradle.api.provider.Property +import org.gradle.api.provider.ProviderFactory import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters +import org.gradle.jvm.toolchain.JavaLauncher +import org.gradle.process.ExecOperations import xyz.jpenilla.runtask.paperapi.DownloadsAPI import xyz.jpenilla.runtask.util.Constants import xyz.jpenilla.runtask.util.Downloader import xyz.jpenilla.runtask.util.InvalidDurationException +import xyz.jpenilla.runtask.util.maybeApplyPaperclip import xyz.jpenilla.runtask.util.parseDuration import xyz.jpenilla.runtask.util.path import xyz.jpenilla.runtask.util.prettyPrint import xyz.jpenilla.runtask.util.sha256 +import xyz.jpenilla.runtask.util.walkMatching import java.io.IOException import java.net.URL +import java.nio.file.Files import java.nio.file.Path import java.nio.file.StandardCopyOption import java.time.Duration @@ -96,11 +102,15 @@ internal abstract class DownloadsAPIServiceImpl : BuildService { versions = loadOrCreateVersions() val versionData = versions.versions.computeIfAbsent(version) { Version(it) } - val buildNumber = resolveBuildNumber(project, versionData, build) + val buildNumber = resolveBuildNumber(providers, versionData, build) + val jarsDir = jarsFor(version) val possible = versionData.knownJars[buildNumber] if (possible != null && !parameters.refreshDependencies.get()) { // We already have this jar! LOGGER.lifecycle("Located {} {} build {} in local cache.", displayName, version, buildNumber) + if (possible.classpath != null && possible.classpath.isNotEmpty()) { + return possible.classpath.flatMap { jarsDir.walkMatching(it) } + } + + requireNotNull(possible.fileName) + requireNotNull(possible.sha256) + // Verify hash is still correct - val localJar = jarsFor(version).resolve(possible.fileName) + val localJar = jarsDir.resolve(possible.fileName) val localBuildHash = localJar.sha256() if (localBuildHash == possible.sha256) { if (build is DownloadsAPIService.Build.Specific) { @@ -141,7 +162,36 @@ internal abstract class DownloadsAPIServiceImpl : BuildService + stream.sorted(Comparator.reverseOrder()).forEach { Files.deleteIfExists(it) } + } + versionData.knownJars[buildNumber] = possible.copy(classpath = emptyList()) + writeVersions() + return listOf(localJar) + } + } else if (possible.classpath.isEmpty()) { + return listOf(localJar) + } } versionData.knownJars.remove(buildNumber) writeVersions() @@ -181,27 +231,40 @@ internal abstract class DownloadsAPIServiceImpl : BuildService Actual: {}", actual) } - private fun updateCheckFrequency(project: Project): Duration { - var prop = project.findProperty(Constants.Properties.UPDATE_CHECK_FREQUENCY) + private fun updateCheckFrequency(providers: ProviderFactory): Duration { + var prop = providers.gradleProperty(Constants.Properties.UPDATE_CHECK_FREQUENCY).orNull if (prop == null) { - prop = project.findProperty(Constants.Properties.UPDATE_CHECK_FREQUENCY_LEGACY) + prop = providers.gradleProperty(Constants.Properties.UPDATE_CHECK_FREQUENCY_LEGACY).orNull if (prop != null) { LOGGER.warn( "Use of legacy '{}' property detected. Please replace with '{}'.", @@ -263,7 +326,7 @@ internal abstract class DownloadsAPIServiceImpl : BuildService?, val keep: Boolean = false ) diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/task/AbstractRun.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/task/AbstractRun.kt index 4d3a6b6..039ed0c 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/task/AbstractRun.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/task/AbstractRun.kt @@ -22,11 +22,13 @@ import org.gradle.api.file.ProjectLayout import org.gradle.api.file.RegularFile import org.gradle.api.provider.Property import org.gradle.api.provider.Provider +import org.gradle.api.provider.ProviderFactory import org.gradle.api.tasks.Classpath import org.gradle.api.tasks.Input import org.gradle.api.tasks.Internal import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.Optional +import org.gradle.process.ExecOperations import xyz.jpenilla.runtask.service.DownloadsAPIService import xyz.jpenilla.runtask.util.path import java.io.File @@ -88,6 +90,12 @@ public abstract class AbstractRun : JavaExec() { @get:Inject protected abstract val layout: ProjectLayout + @get:Inject + protected abstract val execOperations: ExecOperations + + @get:Inject + protected abstract val providers: ProviderFactory + init { init0() } @@ -113,6 +121,15 @@ public abstract class AbstractRun : JavaExec() { super.exec() } + protected open fun resolveBuild(): List = downloadsApiService.get().resolveBuild( + project, + providers, + javaLauncher.get(), + execOperations, + version.get(), + build.get() + ) + private fun preExec() { standardInput = System.`in` workingDir(runDirectory) @@ -123,11 +140,7 @@ public abstract class AbstractRun : JavaExec() { if (!version.isPresent) { error("'runClasspath' is empty and no version was specified for the '$name' task. Don't know what version to download.") } - downloadsApiService.get().resolveBuild( - project, - version.get(), - build.get() - ) + resolveBuild() } classpath(selectedClasspath) diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/extensions.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/extensions.kt index 45f49d8..61469df 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/extensions.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/extensions.kt @@ -23,6 +23,7 @@ import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.plugins.JavaPluginExtension import org.gradle.api.provider.Provider +import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.TaskContainer import org.gradle.api.tasks.TaskProvider import org.gradle.jvm.toolchain.JavaLauncher @@ -30,6 +31,7 @@ import org.gradle.jvm.toolchain.JavaToolchainService import org.gradle.kotlin.dsl.findByType import org.gradle.kotlin.dsl.named import org.gradle.kotlin.dsl.register +import org.gradle.process.JavaExecSpec import java.util.Locale import kotlin.reflect.KClass @@ -63,3 +65,8 @@ internal fun ExtensiblePolymorphicDomainObjectContainer.regi internal fun String.capitalized(locale: Locale = Locale.ROOT): String = replaceFirstChar { if (it.isLowerCase()) it.titlecase(locale) else it.toString() } + +internal fun JavaExec.spec(): JavaExecSpec { + val spec: JavaExecSpec = JavaExec::class.java.getDeclaredField("javaExecSpec").also { it.isAccessible = true }.get(this) as JavaExecSpec + return spec +} diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/files.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/files.kt index f82ab9b..132a3a3 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/files.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/files.kt @@ -20,7 +20,11 @@ import org.gradle.api.Project import org.gradle.api.file.FileSystemLocation import org.gradle.api.file.FileSystemLocationProperty import org.gradle.api.provider.Provider +import java.nio.file.Files import java.nio.file.Path +import kotlin.io.path.relativeTo +import kotlin.streams.asSequence +import kotlin.use internal val FileSystemLocationProperty<*>.path: Path get() = get().path @@ -36,3 +40,11 @@ internal val FileSystemLocation.path: Path internal val Project.sharedCaches: Path get() = gradle.gradleUserHomeDir.toPath().resolve(Constants.GRADLE_CACHES_DIRECTORY_NAME) + +internal fun Path.walkMatching(glob: String): List = walkMatching { + it.fileSystem.getPathMatcher("glob:$glob").matches(it) +} + +internal fun Path.walkMatching(predicate: (Path) -> Boolean): List = Files.walk(this).use { stream -> + stream.asSequence().filter { p -> predicate(p.relativeTo(this)) }.toList() +} diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/paperclip.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/paperclip.kt new file mode 100644 index 0000000..e809aac --- /dev/null +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/paperclip.kt @@ -0,0 +1,111 @@ +package xyz.jpenilla.runtask.util + +import org.gradle.jvm.toolchain.JavaLauncher +import org.gradle.process.ExecOperations +import org.gradle.process.ExecResult +import java.io.IOException +import java.nio.file.Files +import java.nio.file.Path +import java.util.jar.JarFile +import kotlin.io.path.absolute +import kotlin.io.path.absolutePathString +import kotlin.io.path.createDirectories +import kotlin.io.path.exists +import kotlin.io.path.extension +import kotlin.io.path.isRegularFile +import kotlin.io.path.listDirectoryEntries +import kotlin.io.path.name +import kotlin.io.path.relativeTo +import kotlin.streams.asSequence + +internal fun maybeApplyPaperclip( + javaLauncher: JavaLauncher, + exec: ExecOperations, + file: Path, + workingDir: Path, + resultRelativeTo: Path, +): List? { + val type = isPaperclip(file) + if (type == PaperclipType.NONE) { + return null + } + + if (workingDir.exists()) { + Files.walk(workingDir).use { stream -> + stream.sorted(Comparator.reverseOrder()).forEach { Files.deleteIfExists(it) } + } + } + workingDir.createDirectories() + applyPaperclip(javaLauncher, exec, file, workingDir) + + val classpath = mutableListOf() + val classpathPaths = mutableListOf() + + if (type == PaperclipType.MODERN) { + val patchedJar = Files.walk(workingDir.resolve("versions")).use { stream -> + stream.asSequence().filter { it.isRegularFile() && it.extension == "jar" }.single() + } + classpath += patchedJar.relativeTo(resultRelativeTo).toString() + classpathPaths.add(patchedJar.normalize().absolute()) + + classpath.add(workingDir.resolve("libraries").relativeTo(resultRelativeTo).toString() + "/**/*.jar") + val libs = workingDir.walkMatching("libraries/**/*.jar") + classpathPaths.addAll(libs) + } else if (type == PaperclipType.LEGACY) { + val patchedJar = workingDir.resolve("cache") + .listDirectoryEntries() + .single { it.name.startsWith("patched") && it.name.endsWith(".jar") } + classpath += patchedJar.relativeTo(resultRelativeTo).toString() + classpathPaths.add(patchedJar.normalize().absolute()) + } + + // Clean up leftover files in the working dir (i.e. vanilla jar) + Files.walk(workingDir).use { stream -> + stream.forEach { + if (it.isRegularFile() && it.normalize().absolute() !in classpathPaths) { + Files.delete(it) + } + } + } + + return classpath +} + +private enum class PaperclipType { + NONE, + LEGACY, + MODERN +} + +private fun isPaperclip(file: Path): PaperclipType { + if (!file.isRegularFile()) { + return PaperclipType.NONE + } + try { + JarFile(file.toFile()).use { + val main = it.manifest.mainAttributes.getValue("Main-Class") + if (main == "com.destroystokyo.paperclip.Main") { + return PaperclipType.LEGACY + } else if (main == "io.papermc.paperclip.Paperclip") { + return PaperclipType.LEGACY + } else if (main == "io.papermc.paperclip.Main") { + return PaperclipType.MODERN + } + } + } catch (_: IOException) { + return PaperclipType.NONE + } + return PaperclipType.NONE +} + +private fun applyPaperclip( + javaLauncher: JavaLauncher, + exec: ExecOperations, + paperclip: Path, + workingDir: Path, +): ExecResult = exec.javaexec { + executable = javaLauncher.executablePath.path.absolutePathString() + classpath(paperclip) + jvmArgs("-Dpaperclip.patchonly=true") + workingDir(workingDir) +}.assertNormalExitValue() diff --git a/tester/build.gradle.kts b/tester/build.gradle.kts index 70e66e6..8dad4e8 100644 --- a/tester/build.gradle.kts +++ b/tester/build.gradle.kts @@ -1,33 +1,54 @@ import xyz.jpenilla.runpaper.task.RunServer plugins { + java id("xyz.jpenilla.run-paper") id("xyz.jpenilla.run-velocity") id("xyz.jpenilla.run-waterfall") } +java.toolchain { + languageVersion = JavaLanguageVersion.of(21) +} + runPaper.folia.registerTask() val paperPlugins = runPaper.downloadPluginsSpec { - modrinth("carbon", "6dmNHzy8") - github("jpenilla", "MiniMOTD", "v2.1.0", "minimotd-bukkit-2.1.0.jar") - hangar("squaremap", "1.2.3") - url("https://download.luckperms.net/1530/bukkit/loader/LuckPerms-Bukkit-5.4.117.jar") + modrinth("carbon", "WPejrRaD") + github("jpenilla", "MiniMOTD", "v2.1.5", "minimotd-bukkit-2.1.5.jar") + hangar("squaremap", "1.3.4") + url("https://download.luckperms.net/1569/bukkit/loader/LuckPerms-Bukkit-5.4.152.jar") } +val toolchains = javaToolchains tasks { + register("run1_8") { + version = "1.8.8" + runDirectory = layout.projectDirectory.dir("run1_8") + javaLauncher = toolchains.launcherFor { languageVersion = JavaLanguageVersion.of(8) } + } + register("run1_12") { + version = "1.12.2" + runDirectory = layout.projectDirectory.dir("run1_12") + javaLauncher = toolchains.launcherFor { languageVersion = JavaLanguageVersion.of(8) } + } withType { - minecraftVersion("1.20.4") - runDirectory.set(layout.projectDirectory.dir("runServer")) + version.convention("1.21.4") + runDirectory.convention(layout.projectDirectory.dir("runServer")) + } + runServer { + downloadPlugins.from(paperPlugins) + } + runPaper.folia.task { downloadPlugins.from(paperPlugins) } runVelocity { - version("3.3.0-SNAPSHOT") - runDirectory.set(layout.projectDirectory.dir("runVelocity")) + version = "3.4.0-SNAPSHOT" + runDirectory = layout.projectDirectory.dir("runVelocity") downloadPlugins { - modrinth("minimotd", "z8DFFJMR") - hangar("Carbon", "3.0.0-beta.26") - url("https://download.luckperms.net/1530/velocity/LuckPerms-Velocity-5.4.117.jar") + modrinth("minimotd", "nFRYRCht") + hangar("Carbon", "3.0.0-beta.27") + url("https://download.luckperms.net/1569/velocity/LuckPerms-Velocity-5.4.152.jar") } } } From d1cb12d3319f7e0fef1b16a635c4b9db5089e9d1 Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Thu, 9 Jan 2025 22:16:50 -0800 Subject: [PATCH 2/7] JarInfo -> BuildInfo --- .../xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt index be904ad..cf49140 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt @@ -249,7 +249,7 @@ internal abstract class DownloadsAPIServiceImpl : BuildService = HashMap(), + val knownJars: MutableMap = HashMap(), ) } From 7cfc4c8301b0db64a70afa5692a0119bfeb68f6b Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Thu, 9 Jan 2025 22:25:42 -0800 Subject: [PATCH 3/7] Clean up empty parent directories --- .../runtask/service/DownloadsAPIServiceImpl.kt | 12 +++++++----- .../main/kotlin/xyz/jpenilla/runtask/util/files.kt | 7 +++++++ .../kotlin/xyz/jpenilla/runtask/util/paperclip.kt | 1 + 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt index cf49140..4fb2bfa 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt @@ -35,6 +35,7 @@ import xyz.jpenilla.runtask.paperapi.DownloadsAPI import xyz.jpenilla.runtask.util.Constants import xyz.jpenilla.runtask.util.Downloader import xyz.jpenilla.runtask.util.InvalidDurationException +import xyz.jpenilla.runtask.util.deleteEmptyParents import xyz.jpenilla.runtask.util.maybeApplyPaperclip import xyz.jpenilla.runtask.util.parseDuration import xyz.jpenilla.runtask.util.path @@ -102,14 +103,15 @@ internal abstract class DownloadsAPIServiceImpl : BuildService = walkMatching { internal fun Path.walkMatching(predicate: (Path) -> Boolean): List = Files.walk(this).use { stream -> stream.asSequence().filter { p -> predicate(p.relativeTo(this)) }.toList() } + +internal fun Path.deleteEmptyParents() { + if (Files.isDirectory(parent) && Files.list(parent).use { s -> s.toList().isEmpty() }) { + Files.deleteIfExists(parent) + parent.deleteEmptyParents() + } +} diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/paperclip.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/paperclip.kt index e809aac..4635606 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/paperclip.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/paperclip.kt @@ -64,6 +64,7 @@ internal fun maybeApplyPaperclip( stream.forEach { if (it.isRegularFile() && it.normalize().absolute() !in classpathPaths) { Files.delete(it) + it.deleteEmptyParents() } } } From 3740c978179880ec9c012dda04fe151689476bb8 Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Thu, 9 Jan 2025 22:33:09 -0800 Subject: [PATCH 4/7] Remove execution time reference to Project --- .../pluginsapi/PluginDownloadService.kt | 3 +- .../pluginsapi/PluginDownloadServiceImpl.kt | 33 +++++------ .../runtask/service/DownloadsAPIService.kt | 3 +- .../service/DownloadsAPIServiceImpl.kt | 5 +- .../xyz/jpenilla/runtask/task/AbstractRun.kt | 6 +- .../jpenilla/runtask/task/RunWithPlugins.kt | 2 +- .../xyz/jpenilla/runtask/util/Downloader.kt | 17 +++--- .../runtask/util/ProgressLoggerUtil.kt | 56 ------------------- 8 files changed, 37 insertions(+), 88 deletions(-) delete mode 100644 plugin/src/main/kotlin/xyz/jpenilla/runtask/util/ProgressLoggerUtil.kt diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/pluginsapi/PluginDownloadService.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/pluginsapi/PluginDownloadService.kt index 83ecf62..acf268c 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/pluginsapi/PluginDownloadService.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/pluginsapi/PluginDownloadService.kt @@ -23,6 +23,7 @@ import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters +import org.gradle.internal.logging.progress.ProgressLoggerFactory import org.gradle.kotlin.dsl.registerIfAbsent import xyz.jpenilla.runtask.paperapi.Projects import xyz.jpenilla.runtask.util.Constants @@ -53,7 +54,7 @@ public interface PluginDownloadService : BuildService): Provider { diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/pluginsapi/PluginDownloadServiceImpl.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/pluginsapi/PluginDownloadServiceImpl.kt index 1f1ecfc..cf4f6cc 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/pluginsapi/PluginDownloadServiceImpl.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/pluginsapi/PluginDownloadServiceImpl.kt @@ -23,6 +23,7 @@ import com.fasterxml.jackson.module.kotlin.kotlinModule import com.fasterxml.jackson.module.kotlin.readValue import org.gradle.api.Project import org.gradle.api.logging.Logging +import org.gradle.internal.logging.progress.ProgressLoggerFactory import xyz.jpenilla.runtask.util.Constants import xyz.jpenilla.runtask.util.Downloader import xyz.jpenilla.runtask.util.HashingAlgorithm @@ -85,14 +86,14 @@ internal abstract class PluginDownloadServiceImpl : PluginDownloadService { } @Synchronized - override fun resolvePlugin(project: Project, download: PluginApiDownload): Path { + override fun resolvePlugin(progressLoggerFactory: ProgressLoggerFactory, download: PluginApiDownload): Path { manifest = loadOrCreateManifest() return when (download) { - is HangarApiDownload -> resolveHangarPlugin(project, download) - is ModrinthApiDownload -> resolveModrinthPlugin(project, download) - is GitHubApiDownload -> resolveGitHubPlugin(project, download) - is UrlDownload -> resolveUrl(project, download) + is HangarApiDownload -> resolveHangarPlugin(progressLoggerFactory, download) + is ModrinthApiDownload -> resolveModrinthPlugin(progressLoggerFactory, download) + is GitHubApiDownload -> resolveGitHubPlugin(progressLoggerFactory, download) + is UrlDownload -> resolveUrl(progressLoggerFactory, download) } } @@ -101,18 +102,18 @@ internal abstract class PluginDownloadServiceImpl : PluginDownloadService { private val offlineMode: Boolean get() = parameters.offlineMode.get() - private fun resolveUrl(project: Project, download: UrlDownload): Path { + private fun resolveUrl(progressLoggerFactory: ProgressLoggerFactory, download: UrlDownload): Path { val cacheDir = parameters.cacheDirectory.get().asFile.toPath() val targetDir = cacheDir.resolve(Constants.URL_PLUGIN_DIR) val urlHash = download.urlHash() val version = manifest.urlProvider[urlHash] ?: PluginVersion(fileName = "$urlHash.jar", displayName = download.url.get()) val targetFile = targetDir.resolve(version.fileName) val setter: (PluginVersion) -> Unit = { manifest.urlProvider[urlHash] = it } - val ctx = DownloadCtx(project, "url", download.url.get(), targetDir, targetFile, version, setter) + val ctx = DownloadCtx(progressLoggerFactory, "url", download.url.get(), targetDir, targetFile, version, setter) return download(ctx) } - private fun resolveHangarPlugin(project: Project, download: HangarApiDownload): Path { + private fun resolveHangarPlugin(progressLoggerFactory: ProgressLoggerFactory, download: HangarApiDownload): Path { val platformType = parameters.platformType.get() val cacheDir = parameters.cacheDirectory.get().asFile.toPath() @@ -134,11 +135,11 @@ internal abstract class PluginDownloadServiceImpl : PluginDownloadService { val downloadUrl = "$apiUrl/api/v1/projects/$apiPlugin/versions/$apiVersion/$platformType/download" val setter: (PluginVersion) -> Unit = { platform[apiVersion] = it } - val ctx = DownloadCtx(project, apiUrl, downloadUrl, targetDir, targetFile, version, setter) + val ctx = DownloadCtx(progressLoggerFactory, apiUrl, downloadUrl, targetDir, targetFile, version, setter) return download(ctx) } - private fun resolveModrinthPlugin(project: Project, download: ModrinthApiDownload): Path { + private fun resolveModrinthPlugin(progressLoggerFactory: ProgressLoggerFactory, download: ModrinthApiDownload): Path { val cacheDir = parameters.cacheDirectory.get().asFile.toPath() val apiVersion = download.version.get() @@ -156,7 +157,7 @@ internal abstract class PluginDownloadServiceImpl : PluginDownloadService { val versionRequestUrl = "$apiUrl/v2/project/$apiPlugin/version/$apiVersion" val versionJsonPath = download( - DownloadCtx(project, apiUrl, versionRequestUrl, targetDir, jsonFile, jsonVersion, setter = { plugin[jsonVersionName] = it }, requireValidJar = false) + DownloadCtx(progressLoggerFactory, apiUrl, versionRequestUrl, targetDir, jsonFile, jsonVersion, setter = { plugin[jsonVersionName] = it }, requireValidJar = false) ) val versionInfo = mapper.readValue(versionJsonPath.toFile()) val primaryFile = versionInfo.files.find { it.primary } ?: error("Could not find primary file for $download in $versionInfo") @@ -169,11 +170,11 @@ internal abstract class PluginDownloadServiceImpl : PluginDownloadService { val targetFile = targetDir.resolve(version.fileName) return download( - DownloadCtx(project, apiUrl, primaryFile.url, targetDir, targetFile, version, setter = { plugin[apiVersion] = it }) + DownloadCtx(progressLoggerFactory, apiUrl, primaryFile.url, targetDir, targetFile, version, setter = { plugin[apiVersion] = it }) ) } - private fun resolveGitHubPlugin(project: Project, download: GitHubApiDownload): Path { + private fun resolveGitHubPlugin(progressLoggerFactory: ProgressLoggerFactory, download: GitHubApiDownload): Path { val cacheDir = parameters.cacheDirectory.get().asFile.toPath() val owner = download.owner.get() @@ -192,7 +193,7 @@ internal abstract class PluginDownloadServiceImpl : PluginDownloadService { val downloadUrl = "https://github.com/$owner/$repo/releases/download/$tag/$asset" val setter: (PluginVersion) -> Unit = { tagProvider[asset] = it } - val ctx = DownloadCtx(project, "github.com", downloadUrl, targetDir, targetFile, version, setter) + val ctx = DownloadCtx(progressLoggerFactory, "github.com", downloadUrl, targetDir, targetFile, version, setter) return download(ctx) } @@ -262,7 +263,7 @@ internal abstract class PluginDownloadServiceImpl : PluginDownloadService { val opName = "${ctx.baseUrl}:${ctx.version.fileName}" val start = Instant.now() LOGGER.lifecycle("Downloading {}...", displayName) - when (val res = Downloader(url, ctx.targetFile, displayName, opName).download(ctx.project, connection)) { + when (val res = Downloader(url, ctx.targetFile, displayName, opName).download(ctx.progressLoggerFactory, connection)) { is Downloader.Result.Success -> LOGGER.lifecycle("Done downloading {}, took {}.", displayName, Duration.between(start, Instant.now()).prettyPrint()) is Downloader.Result.Failure -> throw IllegalStateException("Failed to download $displayName.", res.throwable) } @@ -311,7 +312,7 @@ internal abstract class PluginDownloadServiceImpl : PluginDownloadService { } private data class DownloadCtx( - val project: Project, + val progressLoggerFactory: ProgressLoggerFactory, val baseUrl: String, val downloadUrl: String, val targetDir: Path, diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIService.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIService.kt index f6a1055..2531879 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIService.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIService.kt @@ -20,6 +20,7 @@ import org.gradle.api.Action import org.gradle.api.Project import org.gradle.api.provider.Provider import org.gradle.api.provider.ProviderFactory +import org.gradle.internal.logging.progress.ProgressLoggerFactory import org.gradle.jvm.toolchain.JavaLauncher import org.gradle.kotlin.dsl.registerIfAbsent import org.gradle.process.ExecOperations @@ -46,10 +47,10 @@ public interface DownloadsAPIService { * @param build build to resolve */ public fun resolveBuild( - project: Project, providers: ProviderFactory, javaLauncher: JavaLauncher, execOperations: ExecOperations, + progressLoggerFactory: ProgressLoggerFactory, version: String, build: Build ): List diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt index 4fb2bfa..53148cf 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt @@ -29,6 +29,7 @@ import org.gradle.api.provider.Property import org.gradle.api.provider.ProviderFactory import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters +import org.gradle.internal.logging.progress.ProgressLoggerFactory import org.gradle.jvm.toolchain.JavaLauncher import org.gradle.process.ExecOperations import xyz.jpenilla.runtask.paperapi.DownloadsAPI @@ -130,10 +131,10 @@ internal abstract class DownloadsAPIServiceImpl : BuildService { @@ -218,7 +219,7 @@ internal abstract class DownloadsAPIServiceImpl : BuildService LOGGER.lifecycle("Done downloading {}, took {}.", displayName, Duration.ofMillis(System.currentTimeMillis() - start).prettyPrint()) is Downloader.Result.Failure -> throw IllegalStateException("Failed to download $displayName.", downloadResult.throwable) } diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/task/AbstractRun.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/task/AbstractRun.kt index 039ed0c..4adf8c7 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/task/AbstractRun.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/task/AbstractRun.kt @@ -28,6 +28,7 @@ import org.gradle.api.tasks.Input import org.gradle.api.tasks.Internal import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.Optional +import org.gradle.internal.logging.progress.ProgressLoggerFactory import org.gradle.process.ExecOperations import xyz.jpenilla.runtask.service.DownloadsAPIService import xyz.jpenilla.runtask.util.path @@ -96,6 +97,9 @@ public abstract class AbstractRun : JavaExec() { @get:Inject protected abstract val providers: ProviderFactory + @get:Inject + protected abstract val progressLoggerFactory: ProgressLoggerFactory + init { init0() } @@ -122,10 +126,10 @@ public abstract class AbstractRun : JavaExec() { } protected open fun resolveBuild(): List = downloadsApiService.get().resolveBuild( - project, providers, javaLauncher.get(), execOperations, + progressLoggerFactory, version.get(), build.get() ) diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/task/RunWithPlugins.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/task/RunWithPlugins.kt index 7ee263c..f83c609 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/task/RunWithPlugins.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/task/RunWithPlugins.kt @@ -87,7 +87,7 @@ public abstract class RunWithPlugins : AbstractRun() { val service = pluginDownloadService.get() for (download in downloadPlugins.downloads) { - ourPluginJars.from(service.resolvePlugin(project, download)) + ourPluginJars.from(service.resolvePlugin(progressLoggerFactory, download)) } } diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/Downloader.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/Downloader.kt index 0853135..edb85dd 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/Downloader.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/Downloader.kt @@ -16,9 +16,9 @@ */ package xyz.jpenilla.runtask.util -import org.gradle.api.Project import org.gradle.api.logging.Logger import org.gradle.api.logging.Logging +import org.gradle.internal.logging.progress.ProgressLoggerFactory import java.io.IOException import java.net.URL import java.net.URLConnection @@ -53,18 +53,18 @@ internal class Downloader( @Volatile private var expectedSize = 0L - fun download(project: Project): Result { + fun download(progressLoggerFactory: ProgressLoggerFactory): Result { if (started) { error("Cannot start download a second time.") } started = true val connection = remote.openConnection() - return download(project, connection) + return download(progressLoggerFactory, connection) } - fun download(project: Project, connection: URLConnection): Result { - val listener = createDownloadListener(project) + fun download(progressLoggerFactory: ProgressLoggerFactory, connection: URLConnection): Result { + val listener = createDownloadListener(progressLoggerFactory) val downloadFuture = CompletableFuture.runAsync { val expected = connection.contentLengthLong @@ -108,11 +108,8 @@ internal class Downloader( return Result.Failure(failure) } - private fun createDownloadListener(project: Project): ProgressListener { - // ProgressLogger is internal Gradle API and can technically be changed, - // (although it hasn't since 3.x) so we access it using reflection, and - // fallback to using LOGGER if it fails - val progressLogger = ProgressLoggerUtil.createProgressLogger(project, operationName) + private fun createDownloadListener(progressLoggerFactory: ProgressLoggerFactory): ProgressListener { + val progressLogger = progressLoggerFactory.newOperation(operationName) return if (progressLogger != null) { LoggingDownloadListener( progressLogger, diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/ProgressLoggerUtil.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/ProgressLoggerUtil.kt deleted file mode 100644 index dacc0bc..0000000 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/util/ProgressLoggerUtil.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Run Task Gradle Plugins - * Copyright (c) 2024 Jason Penilla - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package xyz.jpenilla.runtask.util - -import org.gradle.api.Project -import java.lang.reflect.Method - -internal object ProgressLoggerUtil { - fun createProgressLogger(project: Project, operationName: String): ProgressLoggerWrapper? = try { - val serviceFactory = project.javaClass.getMethod("getServices").invoke(project) - val get = serviceFactory.javaClass.getMethod("get", Class::class.java) - val progressLoggerFactoryClass = Class.forName("org.gradle.internal.logging.progress.ProgressLoggerFactory") - val factory = get(serviceFactory, progressLoggerFactoryClass) - val newOperation = progressLoggerFactoryClass.getMethod("newOperation", String::class.java) - val progressLoggerClass = Class.forName("org.gradle.internal.logging.progress.ProgressLogger") - val start = progressLoggerClass.getMethod("start", String::class.java, String::class.java) - val progress = progressLoggerClass.getMethod("progress", String::class.java) - val completed = progressLoggerClass.getMethod("completed") - ProgressLoggerWrapper(newOperation(factory, operationName), start, progress, completed) - } catch (ex: ReflectiveOperationException) { - null - } - - class ProgressLoggerWrapper( - private val logger: Any, - private val start: Method, - private val progress: Method, - private val completed: Method - ) { - fun start(description: String, status: String) { - start(logger, description, status) - } - - fun progress(status: String) { - progress(logger, status) - } - - fun completed() { - completed(logger) - } - } -} From 9b8fb3477a8f947e72b8ef5b98d1ad603516c7b1 Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Thu, 9 Jan 2025 22:35:04 -0800 Subject: [PATCH 5/7] Run spotless --- .../xyz/jpenilla/runtask/pluginsapi/PluginDownloadServiceImpl.kt | 1 - .../xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/pluginsapi/PluginDownloadServiceImpl.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/pluginsapi/PluginDownloadServiceImpl.kt index cf4f6cc..9305ca4 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/pluginsapi/PluginDownloadServiceImpl.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/pluginsapi/PluginDownloadServiceImpl.kt @@ -21,7 +21,6 @@ import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.module.kotlin.kotlinModule import com.fasterxml.jackson.module.kotlin.readValue -import org.gradle.api.Project import org.gradle.api.logging.Logging import org.gradle.internal.logging.progress.ProgressLoggerFactory import xyz.jpenilla.runtask.util.Constants diff --git a/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt b/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt index 53148cf..ae6d07c 100644 --- a/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt +++ b/plugin/src/main/kotlin/xyz/jpenilla/runtask/service/DownloadsAPIServiceImpl.kt @@ -21,7 +21,6 @@ import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.module.kotlin.kotlinModule import com.fasterxml.jackson.module.kotlin.readValue import org.gradle.api.InvalidUserDataException -import org.gradle.api.Project import org.gradle.api.file.DirectoryProperty import org.gradle.api.logging.Logger import org.gradle.api.logging.Logging From c6abbcb15aca902301f6778304fa9eb7234f278d Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Thu, 9 Jan 2025 22:56:48 -0800 Subject: [PATCH 6/7] Update testing JVMs --- tester/build.gradle.kts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tester/build.gradle.kts b/tester/build.gradle.kts index 8dad4e8..79d93f8 100644 --- a/tester/build.gradle.kts +++ b/tester/build.gradle.kts @@ -25,12 +25,13 @@ tasks { register("run1_8") { version = "1.8.8" runDirectory = layout.projectDirectory.dir("run1_8") - javaLauncher = toolchains.launcherFor { languageVersion = JavaLanguageVersion.of(8) } + javaLauncher = toolchains.launcherFor { languageVersion = JavaLanguageVersion.of(11) } + ignoreUnsupportedJvm() } register("run1_12") { version = "1.12.2" runDirectory = layout.projectDirectory.dir("run1_12") - javaLauncher = toolchains.launcherFor { languageVersion = JavaLanguageVersion.of(8) } + ignoreUnsupportedJvm() } withType { version.convention("1.21.4") From e792384e9b607c928e9ea06901a353e34b3227cf Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Mon, 13 Jan 2025 11:59:35 -0700 Subject: [PATCH 7/7] Update Carbon --- tester/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tester/build.gradle.kts b/tester/build.gradle.kts index 79d93f8..67f69ed 100644 --- a/tester/build.gradle.kts +++ b/tester/build.gradle.kts @@ -14,7 +14,7 @@ java.toolchain { runPaper.folia.registerTask() val paperPlugins = runPaper.downloadPluginsSpec { - modrinth("carbon", "WPejrRaD") + modrinth("carbon", "DQoDwRaq") github("jpenilla", "MiniMOTD", "v2.1.5", "minimotd-bukkit-2.1.5.jar") hangar("squaremap", "1.3.4") url("https://download.luckperms.net/1569/bukkit/loader/LuckPerms-Bukkit-5.4.152.jar") @@ -48,7 +48,7 @@ tasks { runDirectory = layout.projectDirectory.dir("runVelocity") downloadPlugins { modrinth("minimotd", "nFRYRCht") - hangar("Carbon", "3.0.0-beta.27") + hangar("Carbon", "3.0.0-beta.28") url("https://download.luckperms.net/1569/velocity/LuckPerms-Velocity-5.4.152.jar") } }