yarn/build.gradle

668 lines
18 KiB
Groovy

buildscript {
repositories {
maven {
name "Fabric Repository"
url 'https://maven.fabricmc.net'
}
mavenCentral()
mavenLocal()
}
dependencies {
classpath "cuchaz:enigma-cli:${project.enigma_version}"
classpath "net.fabricmc:name-proposal:${project.name_proposal_version}"
}
}
plugins {
id 'java' // for constants, packages, javadoc
id 'maven-publish'
id "com.diffplug.spotless" version "6.21.0"
id 'net.fabricmc.filament'
}
def minecraft_version = "1.20.5-pre4"
filament {
minecraftVersion = minecraft_version
}
def ENV = System.getenv()
// Fetch build number from Github Actions
def build_number = ENV.BUILD_NUMBER ?: "local"
def yarnVersion = "${minecraft_version}+build.$build_number"
version = yarnVersion
if (ENV.BRANCH_NAME) {
def branch = ENV.BRANCH_NAME.substring(ENV.BRANCH_NAME.lastIndexOf('/') + 1)
if (minecraft_version != branch) {
throw new IllegalStateException("Branch name (${branch}) does not match the mc version (${minecraft_version})")
}
}
repositories {
mavenCentral()
maven {
name "Fabric Repository"
url 'https://maven.fabricmc.net'
}
maven {
name "Mojang"
url 'https://libraries.minecraft.net/'
}
mavenLocal()
}
configurations {
asm
enigmaRuntime {
extendsFrom asm
}
javadocClasspath
decompileClasspath
mappingPoetJar {
transitive = false
}
mappingPoet {
extendsFrom mappingPoetJar
extendsFrom asm
transitive = true
}
}
def unpickMetaFile = file("unpick-definitions/unpick.json")
dependencies {
enigmaRuntime "cuchaz:enigma-swing:${project.enigma_version}"
enigmaRuntime "net.fabricmc:name-proposal:${project.name_proposal_version}"
enigmaRuntime "net.fabricmc:cfr:${project.cfr_version}"
javadocClasspath "net.fabricmc:fabric-loader:${project.fabric_loader_version}"
javadocClasspath "org.jetbrains:annotations:${project.jetbrains_annotations_version}"
javadocClasspath "com.google.code.findbugs:jsr305:3.0.2" // for some other jsr annotations
decompileClasspath "net.fabricmc:cfr:${project.cfr_version}"
decompileClasspath "org.vineflower:vineflower:${project.vineflower_version}"
mappingPoetJar "net.fabricmc:mappingpoet:${project.mappingpoet_version}"
asm "org.ow2.asm:asm:${project.asm_version}"
asm "org.ow2.asm:asm-tree:${project.asm_version}"
asm "org.ow2.asm:asm-commons:${project.asm_version}"
asm "org.ow2.asm:asm-util:${project.asm_version}"
}
def yarnGroup = "yarn"
def buildMappingGroup = "mapping build"
def mapJarGroup = "jar mapping"
def mappingsDir = file("mappings")
def tempDir = file("build/temp/yarn")
def cacheFilesMinecraft = new File(tempDir, "minecraft")
def libs = new File("build/libs/")
def minecraftLibraries = configurations.minecraftLibraries
import cuchaz.enigma.command.CheckMappingsCommand
import net.fabricmc.filament.task.MapJarTask
import net.fabricmc.filament.task.DownloadTask
import net.fabricmc.filament.task.UnpickJarTask
import net.fabricmc.filament.task.base.WithFileInput
import net.fabricmc.filament.task.base.WithFileOutput
import net.fabricmc.filament.task.enigma.MapSpecializedMethodsTask
import net.fabricmc.filament.task.mappingio.CompleteMappingsTask
import net.fabricmc.filament.task.mappingio.ConvertMappingsTask
import net.fabricmc.filament.task.mappingio.FormatMappingsTask
import net.fabricmc.filament.task.mappingio.MergeMappingsTask
import net.fabricmc.mappingio.format.MappingFormat
import net.fabricmc.nameproposal.MappingNameCompleter
import org.gradle.work.DisableCachingByDefault
import com.diffplug.spotless.LineEnding
import groovy.xml.XmlSlurper
import java.util.zip.GZIPOutputStream
tasks.register('downloadIntermediary', DownloadTask) {
group = buildMappingGroup
url = "https://github.com/FabricMC/intermediary/raw/master/mappings/${minecraft_version}.tiny"
output = new File(cacheFilesMinecraft, "${minecraft_version}-intermediary.tiny")
}
tasks.register('mapIntermediaryJar', MapJarTask) {
dependsOn downloadIntermediary, mergeMinecraftJars
group = mapJarGroup
output = layout.buildDirectory.file("${minecraft_version}-intermediary.jar")
input = mergeMinecraftJars.output
mappings = downloadIntermediary.output
classpath.from minecraftLibraries
from = 'official'
to = 'intermediary'
}
tasks.register('mapServerIntermediaryJar', MapJarTask) {
dependsOn downloadIntermediary, extractBundledServer
group = mapJarGroup
output = layout.buildDirectory.file("${minecraft_version}-server-intermediary.jar")
input = extractBundledServer.output
mappings = downloadIntermediary.output
classpath.from minecraftLibraries
from = 'official'
to = 'intermediary'
}
tasks.register('yarn', EnigmaTask) {
dependsOn mapIntermediaryJar
group = yarnGroup
jar = mapIntermediaryJar.output
mappings = mappingsDir
}
tasks.register('yarnCommon', EnigmaTask) {
group = yarnGroup
jar = mapServerIntermediaryJar.output
mappings = mappingsDir
}
tasks.register('checkMappings') {
group = buildMappingGroup
inputs.dir mappingsDir
inputs.file mapIntermediaryJar.output
def intermediaryJarPath = mapIntermediaryJar.outputFile.absolutePath
doLast {
String[] args = [
intermediaryJarPath,
mappingsDir.getAbsolutePath()
]
try {
new CheckMappingsCommand().run(args)
} catch (IllegalStateException ignored) {
// just print, don't fail the task
}
}
}
tasks.register('mapSpecializedMethods', MapSpecializedMethodsTask) {
intermediaryJarFile = mapIntermediaryJar.output
mappings = mappingsDir
output = new File(tempDir, "yarn-specialized-mappings-v2.tiny")
inputMappingsFormat = "enigma"
outputMappingsFormat = "tinyv2:intermediary:named"
}
tasks.register('completeMappings', CompleteMappingsTask) {
input = mapSpecializedMethods.output
output = new File(tempDir, "yarn-mappings-v2.tiny")
outputFormat = MappingFormat.TINY_2_FILE
}
tasks.register('convertToV1', ConvertMappingsTask) {
input = mapSpecializedMethods.output
output = new File(tempDir, "yarn-mappings.tiny")
outputFormat = MappingFormat.TINY_FILE
}
tasks.register('mergeTiny', MergeMappingsTask) {
group = buildMappingGroup
output = new File(tempDir, "mappings.tiny")
mappingInputs.from downloadIntermediary.output
mappingInputs.from convertToV1.output
outputFormat = MappingFormat.TINY_FILE
}
// Disable the default jar task
jar {
enabled = false
}
tasks.register('tinyJar', Jar) {
dependsOn mergeTiny
group = buildMappingGroup
archiveFileName = "yarn-${yarnVersion}.jar"
destinationDirectory.set(file("build/libs"))
archiveClassifier = ""
from(mergeTiny.output) {
rename { "mappings/mappings.tiny" }
}
manifest {
attributes("Minecraft-Version-Id": minecraft_version)
}
}
tasks.register('compressTiny', FileInputOutput) {
dependsOn tinyJar, mergeTiny
group = buildMappingGroup
input = mergeTiny.output
output = new File(libs, "yarn-tiny-${yarnVersion}.gz")
doLast {
def buffer = new byte[1024]
def fileOutputStream = new FileOutputStream(outputFile)
def outputStream = new GZIPOutputStream(fileOutputStream)
def fileInputStream = new FileInputStream(inputFile)
def length
while ((length = fileInputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length)
}
fileInputStream.close()
outputStream.finish()
outputStream.close()
}
}
clean.doFirst {
delete tempDir, cacheFilesMinecraft
}
sourceSets {
constants
packageDocs // package info files
}
tasks.register('constantsJar', Jar) {
from sourceSets.constants.output
archiveClassifier = "constants"
}
tasks.build.dependsOn "compressTiny","tinyJar","v2UnmergedYarnJar", "v2MergedYarnJar", "javadocJar"
combineUnpickDefinitions {
group = 'unpick'
input = file('unpick-definitions')
output = new File(tempDir, 'definitions.unpick')
}
// Setup the build for the unpicked constants
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
tasks.withType(JavaCompile).configureEach {
it.options.encoding = "UTF-8"
it.options.release = 21
}
tasks.withType(AbstractArchiveTask).configureEach {
it.preserveFileTimestamps = false
it.reproducibleFileOrder = true
}
spotless {
lineEndings = LineEnding.UNIX
java {
licenseHeaderFile(rootProject.file("HEADER"))
}
}
tasks.register('sourcesJar', Jar) {
dependsOn classes
archiveClassifier = "sources"
from sourceSets.constants.allSource
}
// Only build jars for package infos if we need to actually expose stuff like annotation in the future.
build.dependsOn constantsJar
tasks.register('insertAutoGeneratedEnumMappings', FileInputOutput) {
dependsOn mapIntermediaryJar, downloadIntermediary
group = buildMappingGroup
input = completeMappings.output
output = new File(tempDir, "unmerged-named-v2-with-enum.tiny")
inputs.file mapIntermediaryJar.output
inputs.file downloadIntermediary.output
def intermediaryJarPath = mapIntermediaryJar.outputPath
def intermediaryMappingsPath = downloadIntermediary.outputPath
doLast {
MappingNameCompleter.completeNames(
intermediaryJarPath,
inputPath,
intermediaryMappingsPath,
outputPath
)
}
}
remapUnpickDefinitionsIntermediary {
group = 'unpick'
output = new File(tempDir, 'intermediary-definitions.unpick')
mappings = insertAutoGeneratedEnumMappings.output
}
tasks.register('unpickIntermediaryJar', UnpickJarTask) {
group = 'unpick'
input = mapIntermediaryJar.output
output = layout.buildDirectory.file("${minecraft_version}-intermediary-unpicked.jar")
unpickDefinition = remapUnpickDefinitionsIntermediary.output
constantsJarFile = constantsJar.archiveFile
classpath.from minecraftLibraries
}
tasks.register('yarnUnpicked', EnigmaTask) {
dependsOn "unpickIntermediaryJar"
group = yarnGroup
jar = unpickIntermediaryJar.output
mappings = mappingsDir
}
tasks.register('mergeV2', MergeMappingsTask) {
group = buildMappingGroup
output = new File(tempDir, "merged-v2.tiny")
mappingInputs.from downloadIntermediary.output
mappingInputs.from insertAutoGeneratedEnumMappings.output
outputFormat = MappingFormat.TINY_2_FILE
}
tasks.register('v2UnmergedYarnJar', Jar) {
dependsOn insertAutoGeneratedEnumMappings, combineUnpickDefinitions
def mappings = insertAutoGeneratedEnumMappings.output
group = "mapping build"
archiveFileName = "yarn-${yarnVersion}-v2.jar"
from(file(mappings)) {
rename mappings.get().asFile.name, "mappings/mappings.tiny"
}
from(combineUnpickDefinitions.output) {
rename combineUnpickDefinitions.output.get().asFile.name, "extras/definitions.unpick"
}
from(file(unpickMetaFile)) {
expand version: project.unpick_version
rename unpickMetaFile.name, "extras/unpick.json"
}
destinationDirectory.set(file("build/libs"))
manifest {
attributes("Minecraft-Version-Id": minecraft_version)
}
}
tasks.register('v2MergedYarnJar', Jar) {
dependsOn mergeV2
def mappings = mergeV2.outputFile
group = "mapping build"
archiveFileName = "yarn-${yarnVersion}-mergedv2.jar"
from(file(mappings)) {
rename mappings.name, "mappings/mappings.tiny"
}
from(combineUnpickDefinitions.output) {
rename combineUnpickDefinitions.output.get().asFile.name, "extras/definitions.unpick"
}
from(file(unpickMetaFile)) {
expand version: project.unpick_version
rename unpickMetaFile.name, "extras/unpick.json"
}
destinationDirectory.set(file("build/libs"))
manifest {
attributes("Minecraft-Version-Id": minecraft_version)
}
}
tasks.register('mapNamedJar', MapJarTask) {
dependsOn mergeV2, unpickIntermediaryJar
group = mapJarGroup
output = layout.buildDirectory.file("${minecraft_version}-named.jar")
input = unpickIntermediaryJar.output
mappings = mergeV2.output
classpath.from minecraftLibraries
from = 'intermediary'
to = 'named'
classMappings = [
"javax/annotation/Nullable" : "org/jetbrains/annotations/Nullable",
"javax/annotation/Nonnull" : "org/jetbrains/annotations/NotNull",
"javax/annotation/concurrent/Immutable": "org/jetbrains/annotations/Unmodifiable"
]
}
def mcLibsDir = file('build/tmp/mclibs')
// Task to copy all the mc libs into a single directory.
tasks.register('syncDependencies', Sync) {
from minecraftLibraries
into mcLibsDir
}
def fakeSourceDir = file(".gradle/temp/fakeSource")
tasks.register('genFakeSource', JavaExec) {
dependsOn mergeV2, mapNamedJar, syncDependencies
group = "javadoc generation"
inputs.file mergeV2.output
inputs.file mapNamedJar.output
inputs.dir mcLibsDir
outputs.dir fakeSourceDir
mainClass = "net.fabricmc.mappingpoet.Main"
classpath configurations.mappingPoet
// use merged v2 so we have all namespaces in jd
args mergeV2.outputFile.getAbsolutePath(), mapNamedJar.outputFile.getAbsolutePath(), fakeSourceDir.getAbsolutePath(), mcLibsDir.getAbsolutePath()
}
def decompileOutput = layout.buildDirectory.file("namedSrc")
tasks.register("deleteDecompilerOutput", Delete) {
delete decompileOutput
}
tasks.register('decompileCFR', JavaExec) {
dependsOn deleteDecompilerOutput
dependsOn mapNamedJar
mainClass = "org.benf.cfr.reader.Main"
classpath.from configurations.decompileClasspath
classpath.from minecraftLibraries
args mapNamedJar.outputFile.getAbsolutePath(), "--outputdir", decompileOutput.get().asFile.absolutePath
}
tasks.register('decompileVineflower', JavaExec) {
dependsOn deleteDecompilerOutput
dependsOn mapNamedJar
mainClass = "org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler"
classpath.from configurations.decompileClasspath
minecraftLibraries.files().forEach { file ->
args "--add-external=${jar.absolutePath}"
}
args "--folder", mapNamedJar.outputFile.getAbsolutePath(), decompileOutput.get().asFile.absolutePath
}
tasks.register("formatMappings", FormatMappingsTask) {
input = file("mappings")
}
javadoc {
dependsOn genFakeSource
group = "javadoc generation"
def mappingPoetJar = project.provider { zipTree configurations.mappingPoetJar.singleFile }
failOnError = false
maxMemory = '2G'
// verbose = true // enable to debug
options {
// verbose() // enable to debug
source = "21"
encoding = 'UTF-8'
charSet = 'UTF-8'
memberLevel = JavadocMemberLevel.PRIVATE
splitIndex true
tags(
'apiNote:a:API Note:',
'implSpec:a:Implementation Requirements:',
'implNote:a:Implementation Note:'
)
taglets "net.fabricmc.mappingpoet.jd.MappingTaglet"
// taglet path, header, extra stylesheet settings deferred
it.use()
addBooleanOption "-allow-script-in-comments", true
addBooleanOption "-ignore-source-errors", true
links(
'https://guava.dev/releases/32.1.2-jre/api/docs/',
'https://www.javadoc.io/doc/com.google.code.gson/gson/2.10.1/',
'https://logging.apache.org/log4j/2.x/javadoc/log4j-api/',
'https://www.slf4j.org/apidocs/',
"https://javadoc.io/doc/org.jetbrains/annotations/${project.jetbrains_annotations_version}/",
'https://javadoc.lwjgl.org/',
'https://fastutil.di.unimi.it/docs/',
'https://javadoc.scijava.org/JOML/',
'https://netty.io/4.1/api/',
'https://www.oshi.ooo/oshi-core-java11/apidocs/',
'https://java-native-access.github.io/jna/5.13.0/javadoc/',
'https://unicode-org.github.io/icu-docs/apidoc/released/icu4j/',
'https://jopt-simple.github.io/jopt-simple/apidocs/',
'https://solutions.weblite.ca/java-objective-c-bridge/docs/',
'https://commons.apache.org/proper/commons-logging/apidocs/',
'https://commons.apache.org/proper/commons-lang/javadocs/api-release/',
'https://commons.apache.org/proper/commons-io/apidocs/',
'https://commons.apache.org/proper/commons-codec/archives/1.15/apidocs/',
'https://commons.apache.org/proper/commons-compress/apidocs/',
'https://hc.apache.org/httpcomponents-client-4.5.x/current/httpclient/apidocs/',
"https://maven.fabricmc.net/docs/fabric-loader-${project.fabric_loader_version}/",
"https://docs.oracle.com/en/java/javase/21/docs/api/"
)
// https://docs.oracle.com/en/java/javase/17/docs/specs/man/javadoc.html#additional-options-provided-by-the-standard-doclet
addBooleanOption 'Xdoclint:html', true
addBooleanOption 'Xdoclint:syntax', true
addBooleanOption 'Xdoclint:reference', true
addBooleanOption 'Xdoclint:accessibility', true
}
source fileTree(fakeSourceDir) + sourceSets.constants.allJava + sourceSets.packageDocs.allJava
classpath = configurations.javadocClasspath.plus minecraftLibraries
def fs = project.services.get(FileSystemOperations.class)
def outputDir = javadoc.destinationDir
doLast {
fs.copy {
from mappingPoetJar
include "copy_on_click.js"
into outputDir
}
}
def tagletClasspath = configurations.mappingPoet.files.toList()
doFirst {
// lazy setting
options {
tagletPath tagletClasspath
header mappingPoetJar.get().filter { it.name == 'javadoc_header.txt' }.singleFile.text.trim() // cannot include line breaks
addFileOption "-add-stylesheet", mappingPoetJar.get().filter { it.name == 'forms.css' }.singleFile
}
}
}
tasks.register('javadocJar', Jar) {
dependsOn javadoc
group = "javadoc generation"
from javadoc.destinationDir
archiveVersion.set yarnVersion
archiveClassifier = 'javadoc'
}
generatePackageInfoMappings {
inputJar = mapIntermediaryJar.output
packageName = "net/minecraft/unused/packageinfo/"
outputDir = file("mappings/net/minecraft/unused/packageinfo")
}
javadocLint {
group = "javadoc generation"
mappingDirectory = file("mappings")
}
check.dependsOn javadocLint
publishing {
publications {
register("maven", MavenPublication) {
groupId 'net.fabricmc'
artifactId "yarn"
version yarnVersion
artifact(compressTiny.output) {
classifier "tiny"
builtBy compressTiny
}
artifact(tinyJar)
artifact(v2UnmergedYarnJar) {
classifier "v2"
}
artifact(v2MergedYarnJar) {
classifier "mergedv2"
}
artifact(constantsJar) {
classifier "constants"
}
artifact sourcesJar
artifact javadocJar
}
}
repositories {
if (ENV.MAVEN_URL) {
maven {
url ENV.MAVEN_URL
credentials {
username ENV.MAVEN_USERNAME
password ENV.MAVEN_PASSWORD
}
}
}
}
}
// A task to ensure that the version being released has not already been released.
tasks.register('checkVersion') {
doFirst {
def xml = new URL("https://maven.fabricmc.net/net/fabricmc/yarn/maven-metadata.xml").text
def metadata = new XmlSlurper().parseText(xml)
def versions = metadata.versioning.versions.version*.text();
if (versions.contains(version)) {
throw new RuntimeException("${version} has already been released!")
}
}
}
publish.mustRunAfter checkVersion
abstract class FileInputOutput extends DefaultTask implements WithFileInput, WithFileOutput {
}
@DisableCachingByDefault
abstract class EnigmaTask extends JavaExec {
@InputFile
abstract RegularFileProperty getJar()
@Input
abstract Property<File> getMappings()
EnigmaTask() {
classpath = project.configurations.enigmaRuntime
mainClass.set('cuchaz.enigma.gui.Main')
jvmArgs "-Xmx2048m"
}
@TaskAction
void exec() {
args '-jar'
args jar.get().asFile.absolutePath
args '-mappings'
args mappings.get().absolutePath
args '-profile'
args 'enigma_profile.json'
super.exec()
}
}