restructure build process
All checks were successful
Publish to snapshot maven / build (push) Successful in 21s

- separate constants
- prevent minecraft and its dependencies from appearing in poms
- rename nested jars to frogmods
- clean up a bit
This commit is contained in:
moehreag 2024-06-11 16:28:11 +02:00
parent e731f57a43
commit 3f25831332
12 changed files with 185 additions and 98 deletions

View file

@ -0,0 +1,15 @@
package dev.frogmc.phytotelma
object Constants {
const val MOD_EXTENSION = ".frogmod"
const val MOD_METADATA_FILE = "frog.mod.toml"
const val MINECRAFT_CONFIGURATION = "minecraftDependency"
const val INCLUDE_CONFIGURATION = "include"
const val TASK_GROUP = "frogmc"
const val BUILD_TASK = "buildFrogmod"
const val UPDATE_AW_TASK = "updateAccesswidener"
const val DOWNLOAD_ASSETS_TASK = "downloadAssets"
const val GEN_RUN_CONFIGS_TASK = "genRunConfigs"
const val RUN_CLIENT_TASK = "runClient"
const val RUNT_SERVER_TASK = "runServer"
}

View file

@ -1,15 +1,10 @@
package dev.frogmc.phytotelma
import com.electronwill.nightconfig.core.CommentedConfig
import com.electronwill.nightconfig.core.file.FileNotFoundAction
import com.electronwill.nightconfig.core.io.WritingMode
import com.electronwill.nightconfig.toml.TomlParser
import com.electronwill.nightconfig.toml.TomlWriter
import dev.frogmc.phytotelma.accesswidener.AccessWidener
import dev.frogmc.phytotelma.build.PhytotelmaBuildTask
import dev.frogmc.phytotelma.common.Env
import dev.frogmc.phytotelma.ext.PhytotelmaGradleExtension
import dev.frogmc.phytotelma.ext.PhytotelmaGradleExtensionImpl
import dev.frogmc.phytotelma.nest.Nester
import dev.frogmc.phytotelma.run.AssetDownloader
import dev.frogmc.phytotelma.run.RunConfigGenerator
import dev.frogmc.phytotelma.run.task.RunGameTask
@ -18,26 +13,23 @@ import dev.frogmc.thyroxine.provider.ParchmentProvider
import net.fabricmc.fernflower.api.IFabricJavadocProvider
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlugin
import org.jetbrains.java.decompiler.main.Fernflower
import org.jetbrains.java.decompiler.main.decompiler.PrintStreamLogger
import org.jetbrains.java.decompiler.main.decompiler.SingleFileSaver
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences
import java.io.PrintStream
import java.net.URI
import java.nio.charset.StandardCharsets
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import kotlin.io.path.*
import kotlin.io.path.createDirectories
import kotlin.io.path.deleteExisting
import kotlin.io.path.exists
class PhytotelmaPlugin : Plugin<Project> {
private val taskGroup = "frogmc"
override fun apply(project: Project) {
println("> Applying FrogMC Gradle Plugin")
println("> Applying FrogMC Gradle Plugin to ${project.name}")
globalCacheDir = project.gradle.gradleUserHomeDir.resolve("caches/phytotelma/").toPath()
globalCacheDir.createDirectories()
localCacheDir = project.projectDir.resolve(".gradle/phytotelma/cache/").toPath()
@ -78,7 +70,7 @@ class PhytotelmaPlugin : Plugin<Project> {
project.extensions.findByType(PhytotelmaGradleExtension::class.java) ?: return
project.task("genSources").apply {
group = taskGroup
group = Constants.TASK_GROUP
doFirst {
val fileName = remappedGameJarPath.fileName.toString()
val output =
@ -125,71 +117,42 @@ class PhytotelmaPlugin : Plugin<Project> {
}
project.task("genRunConfigs").apply {
group = taskGroup
project.task(Constants.GEN_RUN_CONFIGS_TASK).apply {
group = Constants.TASK_GROUP
doFirst {
RunConfigGenerator.generate(project)
}
}
project.tasks.register("runClient", RunGameTask::class.java, Env.CLIENT)
project.tasks.register("runServer", RunGameTask::class.java, Env.SERVER)
project.tasks.register(Constants.RUN_CLIENT_TASK, RunGameTask::class.java, Env.CLIENT)
project.tasks.register(Constants.RUNT_SERVER_TASK, RunGameTask::class.java, Env.SERVER)
project.task("downloadAssets").apply {
group = taskGroup
project.task(Constants.DOWNLOAD_ASSETS_TASK).apply {
group = Constants.TASK_GROUP
doFirst {
AssetDownloader.download()
}
}
val includeConfiguration = project.configurations.register("include") {
project.configurations.register(Constants.INCLUDE_CONFIGURATION) {
it.isCanBeResolved = true
it.isCanBeConsumed = false
}
project.tasks.getByName("jar") { task ->
task.outputs.upToDateWhen { false }
task.actions.addLast { _ ->
task.outputs.files.forEach { file ->
val output = file.toPath().parent.resolveSibling("frogmc")
output.createDirectories()
if (file.name.endsWith(".jar") && !(file.name.contains("-dev.") || file.name.contains("-sources."))) {
val outFile = output.resolve(file.name.substring(0, file.name.length - 4) + ".frogmod")
Files.copy(file.toPath(), outFile, StandardCopyOption.REPLACE_EXISTING)
FileSystems.newFileSystem(outFile).use { fs ->
if (includeConfiguration.isPresent) {
val jijPath = fs.getPath("META-INF/jars")
val files = Nester.run(includeConfiguration.get(), jijPath).map { it.toml() }.toList()
if (files.isNotEmpty()) {
val manifest = fs.getPath("frog.mod.toml")
val config: CommentedConfig =
TomlParser().parse(manifest, FileNotFoundAction.THROW_ERROR)
if (!config.add("frog.extensions.included_jars", listOf(files))) {
println("Failed to add included jars to mod manifest, make sure it doesn't include a key at 'frog.extensions.included_jars'!")
}
TomlWriter().write(config, manifest, WritingMode.REPLACE)
}
}
val manifest = fs.getPath("META-INF/MANIFEST.MF")
val lines = manifest.readLines().filter { it.isNotBlank() }
.plus(
"""
Built-By: Phytotelma ${this.javaClass.`package`.implementationVersion}
Target-Namespace: Mojmap
Built-For: Minecraft $minecraftVersion
""".trimIndent()
)
manifest.writeLines(lines, StandardCharsets.UTF_8)
}
println("Built mod to ${outFile.toUri()}")
}
}
}
project.configurations.register(Constants.MINECRAFT_CONFIGURATION) {
project.configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME).extendsFrom(it)
project.configurations.getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME).extendsFrom(it)
it.isCanBeResolved = false
it.isCanBeConsumed = false
it.isTransitive = false
}
project.tasks.register("updateAccesswidener") {
it.group = taskGroup
val buildTask = project.tasks.register(Constants.BUILD_TASK, PhytotelmaBuildTask::class.java)
project.tasks.getByName("build").dependsOn(buildTask)
project.tasks.register(Constants.UPDATE_AW_TASK) {
it.group = Constants.TASK_GROUP
it.actions.addFirst {
AccessWidener.apply(project, remappedGameJarPath)
}

View file

@ -29,7 +29,7 @@ object VersionChecker {
return downloadFile
}
fun savePomFile(version: String, dir: Path){
fun savePomFile(version: String, dir: Path) {
val content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n" +
"\t\t xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
@ -72,7 +72,7 @@ object VersionChecker {
fun downloadAssetIndex(version: String, path: Path): String {
val index = fetchVersionData(version).assetIndex
val dest = path.resolve(index.id+".json")
val dest = path.resolve(index.id + ".json")
if (dest.notExists()) {
CachingHttpClient.getUncached(URI.create(index.url)).use {
Files.copy(it, dest)
@ -109,11 +109,24 @@ private class MojangResponse(val latest: Latest, val versions: List<Version>)
private class Latest(val release: String, val snapshot: String)
private class Version(val id: String, val type: String, val url: String, val time: String, val releaseTime: String, val sha1: String, val complianceLevel: Int)
private class Version(
val id: String,
val type: String,
val url: String,
val time: String,
val releaseTime: String,
val sha1: String,
val complianceLevel: Int
)
private class VersionUrl(val id: String, val url: String)
class VersionData(val downloads: VersionDownloads, val libraries: List<LibraryDownload>, val id: String, val assetIndex: AssetIndex)
class VersionData(
val downloads: VersionDownloads,
val libraries: List<LibraryDownload>,
val id: String,
val assetIndex: AssetIndex
)
class LibraryDownload(val artifact: LibraryArtifact, val name: String)
class LibraryArtifact(val path: String, val sha1: String, val size: Int, val url: String)

View file

@ -3,7 +3,9 @@ package dev.frogmc.phytotelma.accesswidener
import com.electronwill.nightconfig.core.file.FileNotFoundAction
import com.electronwill.nightconfig.toml.TomlParser
import com.google.common.hash.Hashing
import dev.frogmc.phytotelma.Constants
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.JavaPluginExtension
import org.objectweb.asm.*
import java.nio.charset.StandardCharsets
@ -27,7 +29,7 @@ object AccessWidener {
private fun getAWFile(project: Project): Path? {
project.extensions.getByType(JavaPluginExtension::class.java).sourceSets.forEach { set ->
set.resources.filter { it.name == "frog.mod.toml" }.firstOrNull {
set.resources.filter { it.name == Constants.MOD_METADATA_FILE }.firstOrNull {
if (it == null) {
println("Please make sure a 'frog.mod.toml' file is present in the mod's resources!")
return null
@ -43,7 +45,8 @@ object AccessWidener {
}
private fun findDependencyAWs(project: Project): List<Path> {
return project.configurations.getByName("runtimeClasspath").resolvedConfiguration.firstLevelModuleDependencies.flatMap { dep ->
return project.configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)
.resolvedConfiguration.firstLevelModuleDependencies.flatMap { dep ->
dep.moduleArtifacts
}.map { it.file }.map { it.toPath() }.toList()
}
@ -63,7 +66,7 @@ object AccessWidener {
val awFile = getAWFile(project)
println("Found accesswidener in project: $awFile")
return awFile?.bufferedReader(StandardCharsets.UTF_8)
.takeIf { HEADER.test(it?.readLine()?:"") }?.lines()
.takeIf { HEADER.test(it?.readLine() ?: "") }?.lines()
?.map { it.replace("transitive-", "") }
?: Stream.empty()

View file

@ -0,0 +1,80 @@
package dev.frogmc.phytotelma.build
import com.electronwill.nightconfig.core.CommentedConfig
import com.electronwill.nightconfig.core.file.FileNotFoundAction
import com.electronwill.nightconfig.core.io.WritingMode
import com.electronwill.nightconfig.toml.TomlParser
import com.electronwill.nightconfig.toml.TomlWriter
import dev.frogmc.phytotelma.Constants
import dev.frogmc.phytotelma.PhytotelmaPlugin
import dev.frogmc.phytotelma.nest.Nester
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import java.nio.charset.StandardCharsets
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import java.time.LocalDateTime
import kotlin.io.path.createDirectories
import kotlin.io.path.readLines
import kotlin.io.path.writeLines
abstract class PhytotelmaBuildTask : DefaultTask() {
@OutputFile
val outputFile: Path
init {
group = Constants.TASK_GROUP
val includeConfiguration = project.configurations.findByName(Constants.INCLUDE_CONFIGURATION)
val jarTask = project.tasks.getByName("jar")
dependsOn.add(jarTask)
val output = project.layout.buildDirectory.dir("frogmc").get().asFile.toPath()
output.createDirectories()
val abstractArchiveTask = (jarTask as AbstractArchiveTask)
val filename = abstractArchiveTask.archiveFileName.get()
val outFile = output.resolve(filename.substring(0, filename.length - 4) + Constants.MOD_EXTENSION)
outputFile = outFile
outputs.upToDateWhen { false }
inputs.files(jarTask.outputs)
actions.add { task ->
task.inputs.files.forEach { file ->
if (file.name.endsWith(".jar") && !(file.name.contains("-dev.") || file.name.contains("-sources."))) {
Files.copy(file.toPath(), outFile, StandardCopyOption.REPLACE_EXISTING)
FileSystems.newFileSystem(outFile).use { fs ->
if (includeConfiguration != null) {
val jijPath = fs.getPath("META-INF/jars")
val files = Nester.run(includeConfiguration, jijPath).map { it.toml() }.toList()
if (files.isNotEmpty()) {
val manifest = fs.getPath(Constants.MOD_METADATA_FILE)
val config: CommentedConfig =
TomlParser().parse(manifest, FileNotFoundAction.THROW_ERROR)
if (!config.add("frog.extensions.included_jars", listOf(files))) {
println("Failed to add included jars to mod manifest, make sure it doesn't include a key at 'frog.extensions.included_jars'!")
}
TomlWriter().write(config, manifest, WritingMode.REPLACE)
}
}
val manifest = fs.getPath("META-INF/MANIFEST.MF")
val lines = manifest.readLines().filter { it.isNotBlank() }
.plus(
"""
Built-By: Phytotelma ${this.javaClass.`package`.implementationVersion}
Target-Namespace: Mojmap
Built-For: Minecraft ${PhytotelmaPlugin.minecraftVersion}
Build-Date: ${LocalDateTime.now()}
""".trimIndent()
)
manifest.writeLines(lines, StandardCharsets.UTF_8)
}
println("Built mod to ${outFile.toUri()}")
}
}
}
}
}

View file

@ -40,7 +40,7 @@ object CachingHttpClient {
private fun getCacheFile(uri: URI): Path {
val path = PhytotelmaPlugin.globalCacheDir.resolve("httpCache")
.resolve(uri.host+uri.rawPath) // Use rawPath to ensure ASCII compat (since this will be a filesystem dir)
.resolve(uri.host + uri.rawPath) // Use rawPath to ensure ASCII compat (since this will be a filesystem dir)
path.createParentDirectories()
return path
}

View file

@ -1,5 +1,6 @@
package dev.frogmc.phytotelma.ext
import dev.frogmc.phytotelma.Constants
import dev.frogmc.phytotelma.PhytotelmaPlugin
import dev.frogmc.phytotelma.VersionChecker
import dev.frogmc.phytotelma.accesswidener.AccessWidener
@ -10,9 +11,10 @@ import dev.frogmc.thyroxine.provider.MojmapProvider
import dev.frogmc.thyroxine.provider.ParchmentProvider
import org.gradle.api.Project
import javax.inject.Inject
import kotlin.io.path.*
import kotlin.io.path.createParentDirectories
import kotlin.io.path.notExists
abstract class PhytotelmaGradleExtensionImpl: PhytotelmaGradleExtension {
abstract class PhytotelmaGradleExtensionImpl : PhytotelmaGradleExtension {
@Inject
abstract fun getProject(): Project
@ -20,13 +22,15 @@ abstract class PhytotelmaGradleExtensionImpl: PhytotelmaGradleExtension {
override fun minecraft(version: String, parchmentVersion: String?) {
if (VersionChecker.validateVersion(version)) {
println("Setting up Minecraft...")
val parchment = parchmentVersion ?: kotlin.runCatching { ParchmentProvider.findForMinecraftVersion(version) }
val parchment =
parchmentVersion ?: kotlin.runCatching { ParchmentProvider.findForMinecraftVersion(version) }
.getOrDefault("")
PhytotelmaPlugin.minecraftVersion = version
PhytotelmaPlugin.parchmentVersion = parchment
println("Valid version! $version")
val clientJar = VersionChecker.downloadClient(version)
val remappedJar = PhytotelmaPlugin.localCacheDir.resolve("net/minecraft/client/$version/client-$version-remapped.jar")
val remappedJar =
PhytotelmaPlugin.localCacheDir.resolve("net/minecraft/client/$version/client-$version-remapped.jar")
remappedJar.createParentDirectories()
PhytotelmaPlugin.remappedGameJarPath = remappedJar
println("Time to setup Minecraft!")
@ -60,19 +64,22 @@ abstract class PhytotelmaGradleExtensionImpl: PhytotelmaGradleExtension {
}
}
println("Adding dependencies...")
getProject().dependencies.add("implementation", "net.minecrell:terminalconsoleappender:1.2.0")
getProject().dependencies.add(
Constants.MINECRAFT_CONFIGURATION,
"net.minecrell:terminalconsoleappender:1.2.0"
)
VersionChecker.getDependencies(version) {
getProject().dependencies.add("implementation", it)
getProject().dependencies.add(Constants.MINECRAFT_CONFIGURATION, it)
}
VersionChecker.savePomFile(version, remappedJar.parent)
getProject().dependencies.add("implementation", "net.minecraft:client:$version:remapped")
getProject().dependencies.add(Constants.MINECRAFT_CONFIGURATION, "net.minecraft:client:$version:remapped")
println("Generating run configurations...")
RunConfigGenerator.generate(getProject())
if (applyAW) {
getProject().afterEvaluate {
println("Applying AccessWideners..")
println("Applying AccessWideners...")
AccessWidener.apply(getProject(), remappedJar)
}
}

View file

@ -4,6 +4,7 @@ import com.electronwill.nightconfig.core.Config
import com.electronwill.nightconfig.core.UnmodifiableConfig
import com.electronwill.nightconfig.toml.TomlParser
import com.google.common.jimfs.Jimfs
import dev.frogmc.phytotelma.Constants
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.plugins.JavaPlugin
@ -21,7 +22,6 @@ object Nester {
Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix()).use { memFs ->
configuration.dependencies.filterIsInstance<ProjectDependency>().forEach { dependency ->
val project = dependency.dependencyProject
project.getTasksByName(JavaPlugin.JAR_TASK_NAME, false).map { t -> t as AbstractArchiveTask }
.forEach { task ->
val location = task.archiveFile.map {
@ -35,7 +35,8 @@ object Nester {
)
}.get()
path.createDirectories()
val target = path.resolve(location.file.fileName.toString())
val target =
path.resolve(location.file.fileName.toString().replace(".jar", Constants.MOD_EXTENSION))
if (target.notExists()) {
Files.copy(location.file, target)
files.add(
@ -44,6 +45,7 @@ object Nester {
}
}
}
//}
configuration.resolvedConfiguration.firstLevelModuleDependencies.forEach { dep ->
dep.moduleArtifacts.forEach { artifact ->
val location = addMetadata(
@ -55,7 +57,8 @@ object Nester {
memFs
)
path.createDirectories()
val target = path.resolve(location.file.fileName.toString())
val target =
path.resolve(location.file.fileName.toString().replace(".jar", Constants.MOD_EXTENSION))
if (target.notExists()) {
Files.copy(location.file, target)
@ -90,8 +93,8 @@ object Nester {
)
if (tempFile.exists()) {
FileSystems.newFileSystem(tempFile).use {
val metadata = it.getPath("frog.mod.toml")
if (metadata.exists()){
val metadata = it.getPath(Constants.MOD_METADATA_FILE)
if (metadata.exists()) {
return JarMetadata(readModId(metadata), tempFile)
}
}
@ -99,7 +102,8 @@ object Nester {
tempFile.createParentDirectories()
input.copyTo(tempFile)
val modId = ("${group}_$name${if (classifier != null) "_$classifier" else ""}").replace(
"\\.".toRegex(), "_").lowercase(Locale.ROOT)
"\\.".toRegex(), "_"
).lowercase(Locale.ROOT)
FileSystems.newFileSystem(tempFile).use {
it.getPath("frog.mod.toml").writeText(
"""
@ -130,7 +134,7 @@ object Nester {
data class JarMetadata(val modId: String, val file: Path)
class NestedJar(val id: String, val path: String){
class NestedJar(val id: String, val path: String) {
fun toml(): UnmodifiableConfig {
val config = Config.inMemory()
config.add("id", id)

View file

@ -52,7 +52,7 @@ object RunConfigGenerator {
"-Dlog4j2.configurationFile=$log4jPath",
"-Dlog4j2.formatMsgLookups=true"
).apply {
if (project.gradle.startParameter.consoleOutput != ConsoleOutput.Plain){
if (project.gradle.startParameter.consoleOutput != ConsoleOutput.Plain) {
add("-Dfrogmc.log.disableAnsi=false")
}
}.toTypedArray(), if (env == Env.CLIENT) {

View file

@ -25,7 +25,8 @@ class IdeaAdapter : RunConfigAdapter {
val file = folder.resolve("$name.xml")
var module = project.name + "." + project.extensions.getByType(JavaPluginExtension::class.java).sourceSets.getByName(
var module =
project.name + "." + project.extensions.getByType(JavaPluginExtension::class.java).sourceSets.getByName(
SourceSet.MAIN_SOURCE_SET_NAME
).name

View file

@ -1,5 +1,6 @@
package dev.frogmc.phytotelma.run.task
import dev.frogmc.phytotelma.Constants
import dev.frogmc.phytotelma.PhytotelmaPlugin
import dev.frogmc.phytotelma.VersionChecker
import dev.frogmc.phytotelma.common.Env
@ -21,7 +22,7 @@ abstract class RunGameTask @Inject constructor(env: Env) : JavaExec() {
private val classpath: ConfigurableFileCollection = project.objects.fileCollection()
init {
group = "frogmc"
group = Constants.TASK_GROUP
val assetPath = PhytotelmaPlugin.globalCacheDir.resolve("assets").absolute()
val assetIndexPath = assetPath.resolve("indexes")
if (assetIndexPath.notExists()) {
@ -61,7 +62,7 @@ abstract class RunGameTask @Inject constructor(env: Env) : JavaExec() {
writeArgFile()
)
if (project.gradle.startParameter.consoleOutput != ConsoleOutput.Plain){
if (project.gradle.startParameter.consoleOutput != ConsoleOutput.Plain) {
jvmArguments.add("-Dfrogmc.log.disableAnsi=false")
}

View file

@ -1,7 +1,7 @@
package dev.frogmc.phytotelma.vineflower
import net.fabricmc.fernflower.api.IFabricJavadocProvider
import dev.frogmc.thyroxine.api.data.Parchment
import net.fabricmc.fernflower.api.IFabricJavadocProvider
import org.jetbrains.java.decompiler.struct.StructClass
import org.jetbrains.java.decompiler.struct.StructField
import org.jetbrains.java.decompiler.struct.StructMethod