mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-03-27 19:57:00 -05:00
Merge remote-tracking branch 'upstream/exp/1.4' into exp/1.4
# Conflicts: # .gitignore # build.gradle # settings.gradle # src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java # src/main/java/net/fabricmc/loom/configuration/LoomConfigurations.java # src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java # src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java # src/main/java/net/fabricmc/loom/task/service/JarManifestService.java # src/main/java/net/fabricmc/loom/task/service/TinyRemapperService.java # src/main/java/net/fabricmc/loom/util/Constants.java
This commit is contained in:
6
.github/workflows/test-push.yml
vendored
6
.github/workflows/test-push.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
version: [8.1.0-jdk17]
|
version: [8.3.0-jdk17]
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
container:
|
container:
|
||||||
image: gradle:${{ matrix.version }}
|
image: gradle:${{ matrix.version }}
|
||||||
@@ -32,7 +32,7 @@ jobs:
|
|||||||
|
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
container:
|
container:
|
||||||
image: gradle:8.1.0-jdk17
|
image: gradle:8.3.0-jdk17
|
||||||
options: --user root
|
options: --user root
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -51,7 +51,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
version: [8.1.0-jdk17]
|
version: [8.3.0-jdk17]
|
||||||
test: ${{ fromJson(needs.prepare_test_matrix.outputs.matrix) }}
|
test: ${{ fromJson(needs.prepare_test_matrix.outputs.matrix) }}
|
||||||
|
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -22,3 +22,5 @@
|
|||||||
!/checkstyle.xml
|
!/checkstyle.xml
|
||||||
!/codenarc.groovy
|
!/codenarc.groovy
|
||||||
!/bootstrap
|
!/bootstrap
|
||||||
|
|
||||||
|
/src/**/generated
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ plugins {
|
|||||||
id 'groovy'
|
id 'groovy'
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = 8
|
java {
|
||||||
targetCompatibility = 8
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
tasks.withType(JavaCompile).configureEach {
|
||||||
it.options.encoding = "UTF-8"
|
it.options.encoding = "UTF-8"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import org.gradle.util.GradleVersion;
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class LoomGradlePluginBootstrap implements Plugin<PluginAware> {
|
public class LoomGradlePluginBootstrap implements Plugin<PluginAware> {
|
||||||
private static final String MIN_SUPPORTED_GRADLE_VERSION = "8.1";
|
private static final String MIN_SUPPORTED_GRADLE_VERSION = "8.3";
|
||||||
private static final int MIN_SUPPORTED_MAJOR_JAVA_VERSION = 17;
|
private static final int MIN_SUPPORTED_MAJOR_JAVA_VERSION = 17;
|
||||||
private static final int MIN_SUPPORTED_MAJOR_IDEA_VERSION = 2021;
|
private static final int MIN_SUPPORTED_MAJOR_IDEA_VERSION = 2021;
|
||||||
|
|
||||||
|
|||||||
149
build.gradle
149
build.gradle
@@ -8,11 +8,37 @@ plugins {
|
|||||||
id 'checkstyle'
|
id 'checkstyle'
|
||||||
id 'jacoco'
|
id 'jacoco'
|
||||||
id 'codenarc'
|
id 'codenarc'
|
||||||
alias(libs.plugins.kotlin)
|
alias(libs.plugins.kotlin) apply false // Delay this so we can perform magic 🪄 first.
|
||||||
id "com.diffplug.spotless" version "6.18.0"
|
alias(libs.plugins.spotless)
|
||||||
id "org.gradle.test-retry" version "1.5.2"
|
alias(libs.plugins.retry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Haha this is fun :) The Kotlin gradle plugin triggers deprecation warnings for custom configurations (https://youtrack.jetbrains.com/issue/KT-60879)
|
||||||
|
* We need to make DefaultConfiguration.isSpecialCaseOfChangingUsage think that our configurstion is a special case and not deprecated.
|
||||||
|
* We do this by setting DefaultConfiguration.roleAtCreation to LEGACY, thus isInLegacyRole will now return true.
|
||||||
|
*
|
||||||
|
* Yeah I know we can just ignore the deprecation warning, but doing so wouldn't alert us to issues when testing against pre-release Gradle versions. Also this is more fun :)
|
||||||
|
*/
|
||||||
|
def brokenConfigurations = [
|
||||||
|
"commonDecompilerRuntimeClasspath",
|
||||||
|
"fernflowerRuntimeClasspath",
|
||||||
|
"cfrRuntimeClasspath",
|
||||||
|
"vineflowerRuntimeClasspath"
|
||||||
|
]
|
||||||
|
|
||||||
|
configurations.configureEach {
|
||||||
|
if (brokenConfigurations.contains(it.name)) {
|
||||||
|
// For some reason Gradle stops us from using Groovy magic to do this, so lets do it the boring way.
|
||||||
|
def field = org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.class.getDeclaredField("roleAtCreation")
|
||||||
|
field.setAccessible(true)
|
||||||
|
field.set(it, ConfigurationRoles.LEGACY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we apply the Kotlin plugin after, to allow for the above configuration to take place first
|
||||||
|
apply plugin: libs.plugins.kotlin.get().pluginId
|
||||||
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
tasks.withType(JavaCompile).configureEach {
|
||||||
it.options.encoding = "UTF-8"
|
it.options.encoding = "UTF-8"
|
||||||
}
|
}
|
||||||
@@ -24,8 +50,7 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "dev.architectury"
|
group = "dev.architectury"
|
||||||
archivesBaseName = project.name
|
def baseVersion = '1.4'
|
||||||
def baseVersion = '1.3'
|
|
||||||
|
|
||||||
def ENV = System.getenv()
|
def ENV = System.getenv()
|
||||||
def runNumber = ENV.GITHUB_RUN_NUMBER ?: "9999"
|
def runNumber = ENV.GITHUB_RUN_NUMBER ?: "9999"
|
||||||
@@ -74,48 +99,82 @@ configurations.all {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
commonDecompiler {
|
||||||
|
java {
|
||||||
|
srcDir("src/decompilers/common")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fernflower {
|
||||||
|
java {
|
||||||
|
srcDir("src/decompilers/fernflower")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cfr {
|
||||||
|
java {
|
||||||
|
srcDir("src/decompilers/cfr")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vineflower {
|
||||||
|
java {
|
||||||
|
srcDir("src/decompilers/vineflower")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation gradleApi()
|
implementation gradleApi()
|
||||||
|
|
||||||
bootstrap project(":bootstrap")
|
bootstrap project(":bootstrap")
|
||||||
|
|
||||||
// libraries
|
// libraries
|
||||||
implementation ('commons-io:commons-io:2.11.0')
|
implementation libs.commons.io
|
||||||
implementation ('com.google.code.gson:gson:2.10.1')
|
implementation libs.gson
|
||||||
implementation ('com.fasterxml.jackson.core:jackson-databind:2.14.2')
|
implementation libs.jackson
|
||||||
implementation ('com.google.guava:guava:31.1-jre')
|
implementation libs.guava
|
||||||
implementation ('org.ow2.asm:asm:9.5')
|
implementation libs.bundles.asm
|
||||||
implementation ('org.ow2.asm:asm-analysis:9.5')
|
implementation libs.progressbar
|
||||||
implementation ('org.ow2.asm:asm-commons:9.5')
|
|
||||||
implementation ('org.ow2.asm:asm-tree:9.5')
|
|
||||||
implementation ('org.ow2.asm:asm-util:9.5')
|
|
||||||
implementation ('me.tongfei:progressbar:0.9.0')
|
|
||||||
|
|
||||||
// game handling utils
|
// game handling utils
|
||||||
implementation ('net.fabricmc:stitch:0.6.2') {
|
implementation (libs.fabric.stitch) {
|
||||||
exclude module: 'mercury'
|
exclude module: 'mercury'
|
||||||
exclude module: 'enigma'
|
exclude module: 'enigma'
|
||||||
}
|
}
|
||||||
|
|
||||||
// tinyfile management
|
// tinyfile management
|
||||||
implementation ('dev.architectury:tiny-remapper:1.9.21')
|
implementation libs.fabric.tiny.remapper
|
||||||
implementation 'net.fabricmc:access-widener:2.1.0'
|
implementation libs.fabric.access.widener
|
||||||
implementation 'net.fabricmc:mapping-io:0.2.1'
|
implementation libs.fabric.mapping.io
|
||||||
|
|
||||||
implementation ('net.fabricmc:lorenz-tiny:4.0.2') {
|
implementation (libs.fabric.lorenz.tiny) {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
implementation "dev.architectury:refmap-remapper:1.0.5"
|
implementation "dev.architectury:refmap-remapper:1.0.5"
|
||||||
|
|
||||||
// decompilers
|
// decompilers
|
||||||
implementation ('net.fabricmc:fabric-fernflower:2.0.0')
|
fernflowerCompileOnly runtimeLibs.fernflower
|
||||||
implementation ('net.fabricmc:cfr:0.2.1')
|
fernflowerCompileOnly libs.fabric.mapping.io
|
||||||
|
|
||||||
|
cfrCompileOnly runtimeLibs.cfr
|
||||||
|
cfrCompileOnly libs.fabric.mapping.io
|
||||||
|
|
||||||
|
vineflowerCompileOnly runtimeLibs.vineflower
|
||||||
|
vineflowerCompileOnly libs.fabric.mapping.io
|
||||||
|
|
||||||
|
fernflowerApi sourceSets.commonDecompiler.output
|
||||||
|
cfrApi sourceSets.commonDecompiler.output
|
||||||
|
vineflowerApi sourceSets.commonDecompiler.output
|
||||||
|
|
||||||
|
implementation sourceSets.commonDecompiler.output
|
||||||
|
implementation sourceSets.fernflower.output
|
||||||
|
implementation sourceSets.cfr.output
|
||||||
|
implementation sourceSets.vineflower.output
|
||||||
|
|
||||||
// source code remapping
|
// source code remapping
|
||||||
implementation ('dev.architectury:mercury:0.1.2.15')
|
implementation libs.fabric.mercury
|
||||||
|
|
||||||
// Kotlin
|
// Kotlin
|
||||||
implementation('org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.6.2') {
|
implementation(libs.kotlin.metadata) {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,20 +194,21 @@ dependencies {
|
|||||||
|
|
||||||
// Testing
|
// Testing
|
||||||
testImplementation(gradleTestKit())
|
testImplementation(gradleTestKit())
|
||||||
testImplementation('org.spockframework:spock-core:2.3-groovy-3.0') {
|
testImplementation(testLibs.spock) {
|
||||||
exclude module: 'groovy-all'
|
exclude module: 'groovy-all'
|
||||||
}
|
}
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.2'
|
testImplementation testLibs.junit.jupiter.engine
|
||||||
testImplementation ('io.javalin:javalin:5.4.2') {
|
testRuntimeOnly testLibs.junit.platform.launcher
|
||||||
|
testImplementation (testLibs.javalin) {
|
||||||
exclude group: 'org.jetbrains.kotlin'
|
exclude group: 'org.jetbrains.kotlin'
|
||||||
}
|
}
|
||||||
testImplementation 'org.mockito:mockito-core:5.2.0'
|
testImplementation testLibs.mockito
|
||||||
testImplementation 'com.microsoft.java:com.microsoft.java.debug.core:0.46.0'
|
testImplementation testLibs.java.debug
|
||||||
|
|
||||||
compileOnly 'org.jetbrains:annotations:24.0.1'
|
compileOnly runtimeLibs.jetbrains.annotations
|
||||||
testCompileOnly 'org.jetbrains:annotations:24.0.1'
|
testCompileOnly runtimeLibs.jetbrains.annotations
|
||||||
|
|
||||||
testCompileOnly ('net.fabricmc:sponge-mixin:0.11.4+mixin.0.8.5') {
|
testCompileOnly (testLibs.mixin) {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,10 +219,15 @@ jar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
from configurations.bootstrap.collect { it.isDirectory() ? it : zipTree(it) }
|
from configurations.bootstrap.collect { it.isDirectory() ? it : zipTree(it) }
|
||||||
|
from sourceSets.commonDecompiler.output.classesDirs
|
||||||
|
from sourceSets.cfr.output.classesDirs
|
||||||
|
from sourceSets.fernflower.output.classesDirs
|
||||||
|
from sourceSets.vineflower.output.classesDirs
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
base {
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
archivesName = project.name
|
||||||
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
tasks.withType(JavaCompile).configureEach {
|
||||||
it.options.release = 17
|
it.options.release = 17
|
||||||
@@ -170,6 +235,8 @@ tasks.withType(JavaCompile).configureEach {
|
|||||||
|
|
||||||
java {
|
java {
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
|
|
||||||
spotless {
|
spotless {
|
||||||
@@ -203,11 +270,11 @@ spotless {
|
|||||||
|
|
||||||
checkstyle {
|
checkstyle {
|
||||||
configFile = file('checkstyle.xml')
|
configFile = file('checkstyle.xml')
|
||||||
toolVersion = '10.6.0'
|
toolVersion = libs.versions.checkstyle.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
codenarc {
|
codenarc {
|
||||||
toolVersion = "3.2.0"
|
toolVersion = libs.versions.codenarc.get()
|
||||||
configFile = file("codenarc.groovy")
|
configFile = file("codenarc.groovy")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +288,7 @@ gradlePlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
jacoco {
|
jacoco {
|
||||||
toolVersion = "0.8.8"
|
toolVersion = libs.versions.jacoco.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run to get test coverage.
|
// Run to get test coverage.
|
||||||
@@ -230,7 +297,7 @@ jacocoTestReport {
|
|||||||
reports {
|
reports {
|
||||||
xml.required = false
|
xml.required = false
|
||||||
csv.required = false
|
csv.required = false
|
||||||
html.outputLocation = file("${buildDir}/jacocoHtml")
|
html.outputLocation = file("${layout.buildDirectory.get().asFile}/jacocoHtml")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,6 +319,8 @@ test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
import org.gradle.api.internal.artifacts.configurations.ConfigurationRoles
|
||||||
import org.gradle.launcher.cli.KotlinDslVersion
|
import org.gradle.launcher.cli.KotlinDslVersion
|
||||||
import org.gradle.util.GradleVersion
|
import org.gradle.util.GradleVersion
|
||||||
import org.w3c.dom.Document
|
import org.w3c.dom.Document
|
||||||
@@ -265,7 +334,7 @@ publishing {
|
|||||||
// Also publish a snapshot so people can use the latest version if they wish
|
// Also publish a snapshot so people can use the latest version if they wish
|
||||||
snapshot(MavenPublication) { publication ->
|
snapshot(MavenPublication) { publication ->
|
||||||
groupId project.group
|
groupId project.group
|
||||||
artifactId project.archivesBaseName
|
artifactId project.base.archivesName.get()
|
||||||
version baseVersion + '-SNAPSHOT'
|
version baseVersion + '-SNAPSHOT'
|
||||||
|
|
||||||
from components.java
|
from components.java
|
||||||
@@ -403,3 +472,5 @@ class PrintActionsTestName extends DefaultTask {
|
|||||||
new File(System.getenv().GITHUB_OUTPUT) << "\ntest=$sanitised"
|
new File(System.getenv().GITHUB_OUTPUT) << "\ntest=$sanitised"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply from: rootProject.file('gradle/versions.gradle')
|
||||||
|
|||||||
@@ -1,8 +1,54 @@
|
|||||||
[versions]
|
[versions]
|
||||||
kotlin = "1.8.10"
|
kotlin = "1.9.0"
|
||||||
|
asm = "9.5"
|
||||||
|
commons-io = "2.13.0"
|
||||||
|
gson = "2.10.1"
|
||||||
|
jackson = "2.15.2"
|
||||||
|
guava = "32.1.2-jre"
|
||||||
|
|
||||||
|
stitch = "0.6.2"
|
||||||
|
tiny-remapper = "0.8.9"
|
||||||
|
access-widener = "2.1.0"
|
||||||
|
mapping-io = "0.4.2"
|
||||||
|
lorenz-tiny = "4.0.2"
|
||||||
|
mercury = "0.4.0"
|
||||||
|
kotlinx-metadata = "0.7.0"
|
||||||
|
|
||||||
|
# Plugins
|
||||||
|
spotless = "6.20.0"
|
||||||
|
test-retry = "1.5.4"
|
||||||
|
checkstyle = "10.12.2"
|
||||||
|
codenarc = "3.3.0"
|
||||||
|
jacoco = "0.8.10"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
# Loom compile libraries
|
||||||
|
asm = { module = "org.ow2.asm:asm", version.ref = "asm" }
|
||||||
|
asm-analysis = { module = "org.ow2.asm:asm-analysis", version.ref = "asm" }
|
||||||
|
asm-commons = { module = "org.ow2.asm:asm-commons", version.ref = "asm" }
|
||||||
|
asm-tree = { module = "org.ow2.asm:asm-tree", version.ref = "asm" }
|
||||||
|
asm-util = { module = "org.ow2.asm:asm-util", version.ref = "asm" }
|
||||||
|
|
||||||
|
commons-io = { module = "commons-io:commons-io", version.ref = "commons-io" }
|
||||||
|
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
|
||||||
|
jackson = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
|
||||||
|
guava = { module = "com.google.guava:guava", version.ref = "guava" }
|
||||||
|
|
||||||
|
fabric-stitch = { module = "net.fabricmc:stitch", version.ref = "stitch" }
|
||||||
|
fabric-tiny-remapper = { module = "net.fabricmc:tiny-remapper", version.ref = "tiny-remapper" }
|
||||||
|
fabric-access-widener = { module = "net.fabricmc:access-widener", version.ref = "access-widener" }
|
||||||
|
fabric-mapping-io = { module = "net.fabricmc:mapping-io", version.ref = "mapping-io" }
|
||||||
|
fabric-lorenz-tiny = { module = "net.fabricmc:lorenz-tiny", version.ref = "lorenz-tiny" }
|
||||||
|
fabric-mercury = { module = "net.fabricmc:mercury", version.ref = "mercury" }
|
||||||
|
|
||||||
|
# Misc
|
||||||
kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||||
|
kotlin-metadata = { module = "org.jetbrains.kotlinx:kotlinx-metadata-jvm", version.ref = "kotlinx-metadata" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||||
|
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
|
||||||
|
retry = { id = "org.gradle.test-retry", version.ref = "test-retry" }
|
||||||
|
|
||||||
|
[bundles]
|
||||||
|
asm = ["asm", "asm-analysis", "asm-commons", "asm-tree", "asm-util"]
|
||||||
|
|||||||
25
gradle/runtime.libs.versions.toml
Normal file
25
gradle/runtime.libs.versions.toml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
[versions]
|
||||||
|
# Decompilers
|
||||||
|
fernflower = "2.0.0"
|
||||||
|
cfr = "0.2.1"
|
||||||
|
vineflower = "1.9.3"
|
||||||
|
|
||||||
|
# Runtime depedencies
|
||||||
|
mixin-compile-extensions = "0.6.0"
|
||||||
|
dev-launch-injector = "0.2.1+build.8"
|
||||||
|
terminal-console-appender = "1.2.0"
|
||||||
|
jetbrains-annotations = "24.0.1"
|
||||||
|
native-support = "1.0.1"
|
||||||
|
|
||||||
|
[libraries]
|
||||||
|
# Decompilers
|
||||||
|
fernflower = { module = "net.fabricmc:fabric-fernflower", version.ref = "fernflower" }
|
||||||
|
cfr = { module = "net.fabricmc:cfr", version.ref = "cfr" }
|
||||||
|
vineflower = { module = "org.vineflower:vineflower", version.ref = "vineflower" }
|
||||||
|
|
||||||
|
# Runtime depedencies
|
||||||
|
mixin-compile-extensions = { module = "net.fabricmc:fabric-mixin-compile-extensions", version.ref = "mixin-compile-extensions" }
|
||||||
|
dev-launch-injector = { module = "net.fabricmc:dev-launch-injector", version.ref = "dev-launch-injector" }
|
||||||
|
terminal-console-appender = { module = "net.minecrell:terminalconsoleappender", version.ref = "terminal-console-appender" }
|
||||||
|
jetbrains-annotations = { module = "org.jetbrains:annotations", version.ref = "jetbrains-annotations" }
|
||||||
|
native-support = { module = "net.fabricmc:fabric-loom-native-support", version.ref = "native-support" }
|
||||||
23
gradle/test.libs.versions.toml
Normal file
23
gradle/test.libs.versions.toml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
[versions]
|
||||||
|
spock = "2.3-groovy-3.0"
|
||||||
|
junit = "5.10.0"
|
||||||
|
javalin = "5.6.2"
|
||||||
|
mockito = "5.4.0"
|
||||||
|
java-debug = "0.48.0"
|
||||||
|
mixin = "0.11.4+mixin.0.8.5"
|
||||||
|
|
||||||
|
gradle-nightly = "8.5-20230908221250+0000"
|
||||||
|
fabric-loader = "0.14.22"
|
||||||
|
fabric-installer = "0.11.1"
|
||||||
|
|
||||||
|
[libraries]
|
||||||
|
spock = { module = "org.spockframework:spock-core", version.ref = "spock" }
|
||||||
|
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" }
|
||||||
|
junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher" }
|
||||||
|
javalin = { module = "io.javalin:javalin", version.ref = "javalin" }
|
||||||
|
mockito = { module = "org.mockito:mockito-core", version.ref = "mockito" }
|
||||||
|
java-debug = { module = "com.microsoft.java:com.microsoft.java.debug.core", version.ref = "java-debug" }
|
||||||
|
mixin = { module = "net.fabricmc:sponge-mixin", version.ref = "mixin" }
|
||||||
|
gradle-nightly = { module = "org.gradle:dummy", version.ref = "gradle-nightly" }
|
||||||
|
fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-loader" }
|
||||||
|
fabric-installer = { module = "net.fabricmc:fabric-installer", version.ref = "fabric-installer" }
|
||||||
85
gradle/versions.gradle
Normal file
85
gradle/versions.gradle
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/**
|
||||||
|
* Generates a java source file containing all of the version from the Gradle version catalog.
|
||||||
|
*/
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.time.LocalDate
|
||||||
|
|
||||||
|
generateVersionConstants(sourceSets.main, "runtimeLibs", "net/fabricmc/loom/util/LoomVersions")
|
||||||
|
generateVersionConstants(sourceSets.test, "testLibs", "net/fabricmc/loom/test/LoomTestVersions")
|
||||||
|
|
||||||
|
def generateVersionConstants(def sourceSet, def catalogName, def sourcesName) {
|
||||||
|
def versionCatalog = extensions.getByType(VersionCatalogsExtension.class).named(catalogName)
|
||||||
|
|
||||||
|
def task = tasks.register("${catalogName}GenerateConstants", GenerateVersions.class) {
|
||||||
|
versionCatalog.getLibraryAliases().forEach {
|
||||||
|
def lib = versionCatalog.findLibrary(it).get().get()
|
||||||
|
getVersions().put(it, lib.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
className = sourcesName
|
||||||
|
headerFile = file("HEADER")
|
||||||
|
outputDir = file("src/${sourceSet.name}/generated")
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSet.java.srcDir task
|
||||||
|
spotlessGroovyGradle.dependsOn task // Not quite sure why this is needed, but it fixes a warning.
|
||||||
|
compileKotlin.dependsOn task
|
||||||
|
sourcesJar.dependsOn task
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class GenerateVersions extends DefaultTask {
|
||||||
|
@Input
|
||||||
|
abstract MapProperty<String, String> getVersions()
|
||||||
|
|
||||||
|
@Input
|
||||||
|
abstract Property<String> getClassName()
|
||||||
|
|
||||||
|
@InputFile
|
||||||
|
abstract RegularFileProperty getHeaderFile()
|
||||||
|
|
||||||
|
@OutputDirectory
|
||||||
|
abstract DirectoryProperty getOutputDir()
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
def run() {
|
||||||
|
def output = outputDir.get().asFile.toPath()
|
||||||
|
output.deleteDir()
|
||||||
|
|
||||||
|
def className = getClassName().get()
|
||||||
|
def si = className.lastIndexOf("/")
|
||||||
|
def packageName = className.substring(0, si)
|
||||||
|
def packagePath = output.resolve(packageName)
|
||||||
|
def sourceName = className.substring(si + 1, className.length())
|
||||||
|
def sourcePath = packagePath.resolve(sourceName + ".java")
|
||||||
|
Files.createDirectories(packagePath)
|
||||||
|
|
||||||
|
def constants = getVersions().get().collect { entry ->
|
||||||
|
def split = entry.value.split(":")
|
||||||
|
if (split.length != 3) return ""
|
||||||
|
"\tpublic static final ${sourceName} ${toSnakeCase(entry.key)} = new ${sourceName}(\"${split[0]}\", \"${split[1]}\", \"${split[2]}\");"
|
||||||
|
}.findAll { !it.blank }.join("\n")
|
||||||
|
|
||||||
|
def header = headerFile.get().getAsFile().text.replace("\$YEAR", "${LocalDate.now().year}").trim()
|
||||||
|
|
||||||
|
sourcePath.write(
|
||||||
|
"""${header}
|
||||||
|
|
||||||
|
package ${packageName.replace("/", ".")};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto generated class, do not edit.
|
||||||
|
*/
|
||||||
|
public record ${sourceName}(String group, String module, String version) {
|
||||||
|
${constants}
|
||||||
|
|
||||||
|
public String mavenNotation() {
|
||||||
|
return "%s:%s:%s".formatted(group, module, version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
|
||||||
|
static def toSnakeCase(String input) {
|
||||||
|
return input.trim().replaceAll(/[^a-zA-Z0-9]+/, '_').toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,7 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
8
gradlew
vendored
8
gradlew
vendored
@@ -83,7 +83,8 @@ done
|
|||||||
# This is normally unused
|
# This is normally unused
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@@ -130,10 +131,13 @@ location of your Java installation."
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD=java
|
JAVACMD=java
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
|
|||||||
@@ -1,2 +1,14 @@
|
|||||||
rootProject.name = "architectury-loom"
|
rootProject.name = name
|
||||||
|
|
||||||
|
dependencyResolutionManagement {
|
||||||
|
versionCatalogs {
|
||||||
|
testLibs {
|
||||||
|
from(files("gradle/test.libs.versions.toml"))
|
||||||
|
}
|
||||||
|
runtimeLibs {
|
||||||
|
from(files("gradle/runtime.libs.versions.toml"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
include "bootstrap"
|
include "bootstrap"
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ import org.benf.cfr.reader.mapping.NullMapping;
|
|||||||
import org.benf.cfr.reader.util.output.DelegatingDumper;
|
import org.benf.cfr.reader.util.output.DelegatingDumper;
|
||||||
import org.benf.cfr.reader.util.output.Dumper;
|
import org.benf.cfr.reader.util.output.Dumper;
|
||||||
|
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
|
||||||
import net.fabricmc.mappingio.MappingReader;
|
import net.fabricmc.mappingio.MappingReader;
|
||||||
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
|
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
|
||||||
import net.fabricmc.mappingio.tree.MappingTree;
|
import net.fabricmc.mappingio.tree.MappingTree;
|
||||||
@@ -66,7 +65,7 @@ public class CFRObfuscationMapping extends NullMapping {
|
|||||||
private static MappingTree readMappings(Path input) {
|
private static MappingTree readMappings(Path input) {
|
||||||
try (BufferedReader reader = Files.newBufferedReader(input)) {
|
try (BufferedReader reader = Files.newBufferedReader(input)) {
|
||||||
MemoryMappingTree mappingTree = new MemoryMappingTree();
|
MemoryMappingTree mappingTree = new MemoryMappingTree();
|
||||||
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(mappingTree, MappingsNamespace.NAMED.toString());
|
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(mappingTree, "named");
|
||||||
MappingReader.read(reader, nsSwitch);
|
MappingReader.read(reader, nsSwitch);
|
||||||
|
|
||||||
return mappingTree;
|
return mappingTree;
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
package net.fabricmc.loom.decompilers.cfr;
|
package net.fabricmc.loom.decompilers.cfr;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@@ -37,23 +38,18 @@ import java.util.TreeMap;
|
|||||||
import java.util.jar.JarEntry;
|
import java.util.jar.JarEntry;
|
||||||
import java.util.jar.JarOutputStream;
|
import java.util.jar.JarOutputStream;
|
||||||
|
|
||||||
import com.google.common.base.Charsets;
|
|
||||||
import org.benf.cfr.reader.api.OutputSinkFactory;
|
import org.benf.cfr.reader.api.OutputSinkFactory;
|
||||||
import org.benf.cfr.reader.api.SinkReturns;
|
import org.benf.cfr.reader.api.SinkReturns;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import net.fabricmc.loom.util.IOStringConsumer;
|
import net.fabricmc.loom.decompilers.LoomInternalDecompiler;
|
||||||
|
|
||||||
public class CFRSinkFactory implements OutputSinkFactory {
|
public class CFRSinkFactory implements OutputSinkFactory {
|
||||||
private static final Logger ERROR_LOGGER = LoggerFactory.getLogger(CFRSinkFactory.class);
|
|
||||||
|
|
||||||
private final JarOutputStream outputStream;
|
private final JarOutputStream outputStream;
|
||||||
private final IOStringConsumer logger;
|
private final LoomInternalDecompiler.Logger logger;
|
||||||
private final Set<String> addedDirectories = new HashSet<>();
|
private final Set<String> addedDirectories = new HashSet<>();
|
||||||
private final Map<String, Map<Integer, Integer>> lineMap = new TreeMap<>();
|
private final Map<String, Map<Integer, Integer>> lineMap = new TreeMap<>();
|
||||||
|
|
||||||
public CFRSinkFactory(JarOutputStream outputStream, IOStringConsumer logger) {
|
public CFRSinkFactory(JarOutputStream outputStream, LoomInternalDecompiler.Logger logger) {
|
||||||
this.outputStream = outputStream;
|
this.outputStream = outputStream;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
@@ -72,7 +68,7 @@ public class CFRSinkFactory implements OutputSinkFactory {
|
|||||||
return switch (sinkType) {
|
return switch (sinkType) {
|
||||||
case JAVA -> (Sink<T>) decompiledSink();
|
case JAVA -> (Sink<T>) decompiledSink();
|
||||||
case LINENUMBER -> (Sink<T>) lineNumberMappingSink();
|
case LINENUMBER -> (Sink<T>) lineNumberMappingSink();
|
||||||
case EXCEPTION -> (e) -> ERROR_LOGGER.error((String) e);
|
case EXCEPTION -> (e) -> logger.error((String) e);
|
||||||
default -> null;
|
default -> null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -83,7 +79,7 @@ public class CFRSinkFactory implements OutputSinkFactory {
|
|||||||
if (!filename.isEmpty()) filename += "/";
|
if (!filename.isEmpty()) filename += "/";
|
||||||
filename += sinkable.getClassName() + ".java";
|
filename += sinkable.getClassName() + ".java";
|
||||||
|
|
||||||
byte[] data = sinkable.getJava().getBytes(Charsets.UTF_8);
|
byte[] data = sinkable.getJava().getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
writeToJar(filename, data);
|
writeToJar(filename, data);
|
||||||
};
|
};
|
||||||
@@ -45,10 +45,9 @@ import org.benf.cfr.reader.util.getopt.Options;
|
|||||||
import org.benf.cfr.reader.util.getopt.OptionsImpl;
|
import org.benf.cfr.reader.util.getopt.OptionsImpl;
|
||||||
import org.benf.cfr.reader.util.output.SinkDumperFactory;
|
import org.benf.cfr.reader.util.output.SinkDumperFactory;
|
||||||
|
|
||||||
import net.fabricmc.loom.api.decompilers.DecompilationMetadata;
|
import net.fabricmc.loom.decompilers.LoomInternalDecompiler;
|
||||||
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
|
|
||||||
|
|
||||||
public final class LoomCFRDecompiler implements LoomDecompiler {
|
public final class LoomCFRDecompiler implements LoomInternalDecompiler {
|
||||||
private static final Map<String, String> DECOMPILE_OPTIONS = Map.of(
|
private static final Map<String, String> DECOMPILE_OPTIONS = Map.of(
|
||||||
"renameillegalidents", "true",
|
"renameillegalidents", "true",
|
||||||
"trackbytecodeloc", "true",
|
"trackbytecodeloc", "true",
|
||||||
@@ -56,16 +55,18 @@ public final class LoomCFRDecompiler implements LoomDecompiler {
|
|||||||
);
|
);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decompile(Path compiledJar, Path sourcesDestination, Path linemapDestination, DecompilationMetadata metaData) {
|
public void decompile(LoomInternalDecompiler.Context context) {
|
||||||
|
Path compiledJar = context.compiledJar();
|
||||||
|
|
||||||
final String path = compiledJar.toAbsolutePath().toString();
|
final String path = compiledJar.toAbsolutePath().toString();
|
||||||
final Map<String, String> allOptions = new HashMap<>(DECOMPILE_OPTIONS);
|
final Map<String, String> allOptions = new HashMap<>(DECOMPILE_OPTIONS);
|
||||||
allOptions.putAll(metaData.options());
|
allOptions.putAll(context.options());
|
||||||
|
|
||||||
final Options options = OptionsImpl.getFactory().create(allOptions);
|
final Options options = OptionsImpl.getFactory().create(allOptions);
|
||||||
|
|
||||||
ClassFileSourceImpl classFileSource = new ClassFileSourceImpl(options);
|
ClassFileSourceImpl classFileSource = new ClassFileSourceImpl(options);
|
||||||
|
|
||||||
for (Path library : metaData.libraries()) {
|
for (Path library : context.libraries()) {
|
||||||
classFileSource.addJarContent(library.toAbsolutePath().toString(), AnalysisType.JAR);
|
classFileSource.addJarContent(library.toAbsolutePath().toString(), AnalysisType.JAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,8 +74,8 @@ public final class LoomCFRDecompiler implements LoomDecompiler {
|
|||||||
|
|
||||||
DCCommonState state = new DCCommonState(options, classFileSource);
|
DCCommonState state = new DCCommonState(options, classFileSource);
|
||||||
|
|
||||||
if (metaData.javaDocs() != null) {
|
if (context.javaDocs() != null) {
|
||||||
state = new DCCommonState(state, new CFRObfuscationMapping(metaData.javaDocs()));
|
state = new DCCommonState(state, new CFRObfuscationMapping(context.javaDocs()));
|
||||||
}
|
}
|
||||||
|
|
||||||
final Manifest manifest = new Manifest();
|
final Manifest manifest = new Manifest();
|
||||||
@@ -82,8 +83,8 @@ public final class LoomCFRDecompiler implements LoomDecompiler {
|
|||||||
|
|
||||||
Map<String, Map<Integer, Integer>> lineMap;
|
Map<String, Map<Integer, Integer>> lineMap;
|
||||||
|
|
||||||
try (JarOutputStream outputStream = new JarOutputStream(Files.newOutputStream(sourcesDestination), manifest)) {
|
try (JarOutputStream outputStream = new JarOutputStream(Files.newOutputStream(context.sourcesDestination()), manifest)) {
|
||||||
CFRSinkFactory cfrSinkFactory = new CFRSinkFactory(outputStream, metaData.logger());
|
CFRSinkFactory cfrSinkFactory = new CFRSinkFactory(outputStream, context.logger());
|
||||||
SinkDumperFactory dumperFactory = new SinkDumperFactory(cfrSinkFactory, options);
|
SinkDumperFactory dumperFactory = new SinkDumperFactory(cfrSinkFactory, options);
|
||||||
|
|
||||||
Driver.doJar(state, path, AnalysisType.JAR, dumperFactory);
|
Driver.doJar(state, path, AnalysisType.JAR, dumperFactory);
|
||||||
@@ -93,7 +94,7 @@ public final class LoomCFRDecompiler implements LoomDecompiler {
|
|||||||
throw new UncheckedIOException("Failed to decompile", e);
|
throw new UncheckedIOException("Failed to decompile", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeLineMap(linemapDestination, lineMap);
|
writeLineMap(context.linemapDestination(), lineMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeLineMap(Path output, Map<String, Map<Integer, Integer>> lineMap) {
|
private void writeLineMap(Path output, Map<String, Map<Integer, Integer>> lineMap) {
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.decompilers;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
// This is an internal interface to loom, DO NOT USE this in your own plugins.
|
||||||
|
public interface LoomInternalDecompiler {
|
||||||
|
void decompile(Context context);
|
||||||
|
|
||||||
|
interface Context {
|
||||||
|
Path compiledJar();
|
||||||
|
|
||||||
|
Path sourcesDestination();
|
||||||
|
|
||||||
|
Path linemapDestination();
|
||||||
|
|
||||||
|
int numberOfThreads();
|
||||||
|
|
||||||
|
Path javaDocs();
|
||||||
|
|
||||||
|
Collection<Path> libraries();
|
||||||
|
|
||||||
|
Logger logger();
|
||||||
|
|
||||||
|
Map<String, String> options();
|
||||||
|
|
||||||
|
byte[] unpackZip(Path zip, String path) throws IOException;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Logger {
|
||||||
|
void accept(String data) throws IOException;
|
||||||
|
|
||||||
|
void error(String msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019-2021 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.decompilers.fernflower;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jetbrains.java.decompiler.main.Fernflower;
|
||||||
|
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
|
||||||
|
import org.jetbrains.java.decompiler.main.extern.IResultSaver;
|
||||||
|
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||||
|
|
||||||
|
import net.fabricmc.fernflower.api.IFabricJavadocProvider;
|
||||||
|
import net.fabricmc.loom.decompilers.LoomInternalDecompiler;
|
||||||
|
|
||||||
|
public final class FabricFernFlowerDecompiler implements LoomInternalDecompiler {
|
||||||
|
@Override
|
||||||
|
public void decompile(LoomInternalDecompiler.Context context) {
|
||||||
|
Path sourcesDestination = context.sourcesDestination();
|
||||||
|
Path linemapDestination = context.linemapDestination();
|
||||||
|
|
||||||
|
final Map<String, Object> options = new HashMap<>(
|
||||||
|
Map.of(
|
||||||
|
IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES, "1",
|
||||||
|
IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1",
|
||||||
|
IFernflowerPreferences.REMOVE_SYNTHETIC, "1",
|
||||||
|
IFernflowerPreferences.LOG_LEVEL, "trace",
|
||||||
|
IFernflowerPreferences.THREADS, String.valueOf(context.numberOfThreads()),
|
||||||
|
IFernflowerPreferences.INDENT_STRING, "\t",
|
||||||
|
IFabricJavadocProvider.PROPERTY_NAME, new TinyJavadocProvider(context.javaDocs().toFile())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
options.putAll(context.options());
|
||||||
|
|
||||||
|
IResultSaver saver = new ThreadSafeResultSaver(sourcesDestination::toFile, linemapDestination::toFile);
|
||||||
|
Fernflower ff = new Fernflower((externalPath, internalPath) -> FabricFernFlowerDecompiler.this.getBytecode(externalPath, internalPath, context), saver, options, new FernflowerLogger(context.logger()));
|
||||||
|
|
||||||
|
for (Path library : context.libraries()) {
|
||||||
|
ff.addLibrary(library.toFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
ff.addSource(context.compiledJar().toFile());
|
||||||
|
|
||||||
|
try {
|
||||||
|
ff.decompileContext();
|
||||||
|
} finally {
|
||||||
|
ff.clearContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getBytecode(String externalPath, String internalPath, LoomInternalDecompiler.Context context) throws IOException {
|
||||||
|
File file = new File(externalPath);
|
||||||
|
|
||||||
|
if (internalPath == null) {
|
||||||
|
return InterpreterUtil.getBytes(file);
|
||||||
|
} else {
|
||||||
|
return context.unpackZip(file.toPath(), internalPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,12 +28,12 @@ import java.io.IOException;
|
|||||||
|
|
||||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
||||||
|
|
||||||
import net.fabricmc.loom.util.IOStringConsumer;
|
import net.fabricmc.loom.decompilers.LoomInternalDecompiler;
|
||||||
|
|
||||||
public class FernflowerLogger extends IFernflowerLogger {
|
public class FernflowerLogger extends IFernflowerLogger {
|
||||||
private final IOStringConsumer logger;
|
private final LoomInternalDecompiler.Logger logger;
|
||||||
|
|
||||||
public FernflowerLogger(IOStringConsumer logger) {
|
public FernflowerLogger(LoomInternalDecompiler.Logger logger) {
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,16 +35,17 @@ import org.jetbrains.java.decompiler.struct.StructClass;
|
|||||||
import org.jetbrains.java.decompiler.struct.StructField;
|
import org.jetbrains.java.decompiler.struct.StructField;
|
||||||
import org.jetbrains.java.decompiler.struct.StructMethod;
|
import org.jetbrains.java.decompiler.struct.StructMethod;
|
||||||
import org.jetbrains.java.decompiler.struct.StructRecordComponent;
|
import org.jetbrains.java.decompiler.struct.StructRecordComponent;
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
|
|
||||||
import net.fabricmc.fernflower.api.IFabricJavadocProvider;
|
import net.fabricmc.fernflower.api.IFabricJavadocProvider;
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
|
||||||
import net.fabricmc.mappingio.MappingReader;
|
import net.fabricmc.mappingio.MappingReader;
|
||||||
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
|
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
|
||||||
import net.fabricmc.mappingio.tree.MappingTree;
|
import net.fabricmc.mappingio.tree.MappingTree;
|
||||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||||
|
|
||||||
public class TinyJavadocProvider implements IFabricJavadocProvider {
|
public class TinyJavadocProvider implements IFabricJavadocProvider {
|
||||||
|
private static final int ACC_STATIC = 0x0008;
|
||||||
|
private static final int ACC_RECORD = 0x10000;
|
||||||
|
|
||||||
private final MappingTree mappingTree;
|
private final MappingTree mappingTree;
|
||||||
|
|
||||||
public TinyJavadocProvider(File tinyFile) {
|
public TinyJavadocProvider(File tinyFile) {
|
||||||
@@ -93,7 +94,7 @@ public class TinyJavadocProvider implements IFabricJavadocProvider {
|
|||||||
addedParam = true;
|
addedParam = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
parts.add(String.format("@param %s %s", fieldMapping.getName(MappingsNamespace.NAMED.toString()), comment));
|
parts.add(String.format("@param %s %s", fieldMapping.getName("named"), comment));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +152,7 @@ public class TinyJavadocProvider implements IFabricJavadocProvider {
|
|||||||
addedParam = true;
|
addedParam = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
parts.add(String.format("@param %s %s", argMapping.getName(MappingsNamespace.NAMED.toString()), comment));
|
parts.add(String.format("@param %s %s", argMapping.getName("named"), comment));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +169,7 @@ public class TinyJavadocProvider implements IFabricJavadocProvider {
|
|||||||
private static MappingTree readMappings(File input) {
|
private static MappingTree readMappings(File input) {
|
||||||
try (BufferedReader reader = Files.newBufferedReader(input.toPath())) {
|
try (BufferedReader reader = Files.newBufferedReader(input.toPath())) {
|
||||||
MemoryMappingTree mappingTree = new MemoryMappingTree();
|
MemoryMappingTree mappingTree = new MemoryMappingTree();
|
||||||
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(mappingTree, MappingsNamespace.NAMED.toString());
|
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(mappingTree, "named");
|
||||||
MappingReader.read(reader, nsSwitch);
|
MappingReader.read(reader, nsSwitch);
|
||||||
|
|
||||||
return mappingTree;
|
return mappingTree;
|
||||||
@@ -178,10 +179,10 @@ public class TinyJavadocProvider implements IFabricJavadocProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isRecord(StructClass structClass) {
|
public static boolean isRecord(StructClass structClass) {
|
||||||
return (structClass.getAccessFlags() & Opcodes.ACC_RECORD) != 0;
|
return (structClass.getAccessFlags() & ACC_RECORD) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isStatic(StructField structField) {
|
public static boolean isStatic(StructField structField) {
|
||||||
return (structField.getAccessFlags() & Opcodes.ACC_STATIC) != 0;
|
return (structField.getAccessFlags() & ACC_STATIC) != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019-2023 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.decompilers.vineflower;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.jar.JarOutputStream;
|
||||||
|
import java.util.jar.Manifest;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||||
|
import org.jetbrains.java.decompiler.main.extern.IResultSaver;
|
||||||
|
|
||||||
|
public class ThreadSafeResultSaver implements IResultSaver {
|
||||||
|
private final Supplier<File> output;
|
||||||
|
private final Supplier<File> lineMapFile;
|
||||||
|
|
||||||
|
public Map<String, ZipOutputStream> outputStreams = new HashMap<>();
|
||||||
|
public Map<String, ExecutorService> saveExecutors = new HashMap<>();
|
||||||
|
public PrintWriter lineMapWriter;
|
||||||
|
|
||||||
|
public ThreadSafeResultSaver(Supplier<File> output, Supplier<File> lineMapFile) {
|
||||||
|
this.output = output;
|
||||||
|
this.lineMapFile = lineMapFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createArchive(String path, String archiveName, Manifest manifest) {
|
||||||
|
String key = path + "/" + archiveName;
|
||||||
|
File file = output.get();
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileOutputStream fos = new FileOutputStream(file);
|
||||||
|
ZipOutputStream zos = manifest == null ? new ZipOutputStream(fos) : new JarOutputStream(fos, manifest);
|
||||||
|
outputStreams.put(key, zos);
|
||||||
|
saveExecutors.put(key, Executors.newSingleThreadExecutor());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Unable to create archive: " + file, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lineMapFile.get() != null) {
|
||||||
|
try {
|
||||||
|
lineMapWriter = new PrintWriter(new FileWriter(lineMapFile.get()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Unable to create line mapping file: " + lineMapFile.get(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveClassEntry(String path, String archiveName, String qualifiedName, String entryName, String content) {
|
||||||
|
this.saveClassEntry(path, archiveName, qualifiedName, entryName, content, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveClassEntry(String path, String archiveName, String qualifiedName, String entryName, String content, int[] mapping) {
|
||||||
|
String key = path + "/" + archiveName;
|
||||||
|
ExecutorService executor = saveExecutors.get(key);
|
||||||
|
executor.submit(() -> {
|
||||||
|
ZipOutputStream zos = outputStreams.get(key);
|
||||||
|
|
||||||
|
try {
|
||||||
|
zos.putNextEntry(new ZipEntry(entryName));
|
||||||
|
|
||||||
|
if (content != null) {
|
||||||
|
zos.write(content.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
DecompilerContext.getLogger().writeMessage("Cannot write entry " + entryName, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapping != null && lineMapWriter != null) {
|
||||||
|
int maxLine = 0;
|
||||||
|
int maxLineDest = 0;
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = 0; i < mapping.length; i += 2) {
|
||||||
|
maxLine = Math.max(maxLine, mapping[i]);
|
||||||
|
maxLineDest = Math.max(maxLineDest, mapping[i + 1]);
|
||||||
|
builder.append("\t").append(mapping[i]).append("\t").append(mapping[i + 1]).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
lineMapWriter.println(qualifiedName + "\t" + maxLine + "\t" + maxLineDest);
|
||||||
|
lineMapWriter.println(builder.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closeArchive(String path, String archiveName) {
|
||||||
|
String key = path + "/" + archiveName;
|
||||||
|
ExecutorService executor = saveExecutors.get(key);
|
||||||
|
Future<?> closeFuture = executor.submit(() -> {
|
||||||
|
ZipOutputStream zos = outputStreams.get(key);
|
||||||
|
|
||||||
|
try {
|
||||||
|
zos.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Unable to close zip. " + key, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
executor.shutdown();
|
||||||
|
|
||||||
|
try {
|
||||||
|
closeFuture.get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStreams.remove(key);
|
||||||
|
saveExecutors.remove(key);
|
||||||
|
|
||||||
|
if (lineMapWriter != null) {
|
||||||
|
lineMapWriter.flush();
|
||||||
|
lineMapWriter.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveFolder(String path) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copyFile(String source, String path, String entryName) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveClassFile(String path, String qualifiedName, String entryName, String content, int[] mapping) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveDirEntry(String path, String archiveName, String entryName) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copyEntry(String source, String path, String archiveName, String entry) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019-2023 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.decompilers.vineflower;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jetbrains.java.decompiler.struct.StructClass;
|
||||||
|
import org.jetbrains.java.decompiler.struct.StructField;
|
||||||
|
import org.jetbrains.java.decompiler.struct.StructMethod;
|
||||||
|
import org.jetbrains.java.decompiler.struct.StructRecordComponent;
|
||||||
|
|
||||||
|
import net.fabricmc.fernflower.api.IFabricJavadocProvider;
|
||||||
|
import net.fabricmc.mappingio.MappingReader;
|
||||||
|
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
|
||||||
|
import net.fabricmc.mappingio.tree.MappingTree;
|
||||||
|
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||||
|
|
||||||
|
public class TinyJavadocProvider implements IFabricJavadocProvider {
|
||||||
|
private static final int ACC_STATIC = 0x0008;
|
||||||
|
private static final int ACC_RECORD = 0x10000;
|
||||||
|
|
||||||
|
private final MappingTree mappingTree;
|
||||||
|
|
||||||
|
public TinyJavadocProvider(File tinyFile) {
|
||||||
|
mappingTree = readMappings(tinyFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getClassDoc(StructClass structClass) {
|
||||||
|
MappingTree.ClassMapping classMapping = mappingTree.getClass(structClass.qualifiedName);
|
||||||
|
|
||||||
|
if (classMapping == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRecord(structClass)) {
|
||||||
|
return classMapping.getComment();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the record component docs here.
|
||||||
|
*
|
||||||
|
* Record components are mapped via the field name, thus take the docs from the fields and display them on then class.
|
||||||
|
*/
|
||||||
|
List<String> parts = new ArrayList<>();
|
||||||
|
|
||||||
|
if (classMapping.getComment() != null) {
|
||||||
|
parts.add(classMapping.getComment());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean addedParam = false;
|
||||||
|
|
||||||
|
for (StructRecordComponent component : structClass.getRecordComponents()) {
|
||||||
|
// The component will always match the field name and descriptor
|
||||||
|
MappingTree.FieldMapping fieldMapping = classMapping.getField(component.getName(), component.getDescriptor());
|
||||||
|
|
||||||
|
if (fieldMapping == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String comment = fieldMapping.getComment();
|
||||||
|
|
||||||
|
if (comment != null) {
|
||||||
|
if (!addedParam && classMapping.getComment() != null) {
|
||||||
|
//Add a blank line before components when the class has a comment
|
||||||
|
parts.add("");
|
||||||
|
addedParam = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
parts.add(String.format("@param %s %s", fieldMapping.getName("named"), comment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.join("\n", parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFieldDoc(StructClass structClass, StructField structField) {
|
||||||
|
// None static fields in records are handled in the class javadoc.
|
||||||
|
if (isRecord(structClass) && !isStatic(structField)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
MappingTree.ClassMapping classMapping = mappingTree.getClass(structClass.qualifiedName);
|
||||||
|
|
||||||
|
if (classMapping == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
MappingTree.FieldMapping fieldMapping = classMapping.getField(structField.getName(), structField.getDescriptor());
|
||||||
|
|
||||||
|
return fieldMapping != null ? fieldMapping.getComment() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMethodDoc(StructClass structClass, StructMethod structMethod) {
|
||||||
|
MappingTree.ClassMapping classMapping = mappingTree.getClass(structClass.qualifiedName);
|
||||||
|
|
||||||
|
if (classMapping == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
MappingTree.MethodMapping methodMapping = classMapping.getMethod(structMethod.getName(), structMethod.getDescriptor());
|
||||||
|
|
||||||
|
if (methodMapping != null) {
|
||||||
|
List<String> parts = new ArrayList<>();
|
||||||
|
|
||||||
|
if (methodMapping.getComment() != null) {
|
||||||
|
parts.add(methodMapping.getComment());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean addedParam = false;
|
||||||
|
|
||||||
|
for (MappingTree.MethodArgMapping argMapping : methodMapping.getArgs()) {
|
||||||
|
String comment = argMapping.getComment();
|
||||||
|
|
||||||
|
if (comment != null) {
|
||||||
|
if (!addedParam && methodMapping.getComment() != null) {
|
||||||
|
//Add a blank line before params when the method has a comment
|
||||||
|
parts.add("");
|
||||||
|
addedParam = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
parts.add(String.format("@param %s %s", argMapping.getName("named"), comment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.join("\n", parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MappingTree readMappings(File input) {
|
||||||
|
try (BufferedReader reader = Files.newBufferedReader(input.toPath())) {
|
||||||
|
MemoryMappingTree mappingTree = new MemoryMappingTree();
|
||||||
|
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(mappingTree, "named");
|
||||||
|
MappingReader.read(reader, nsSwitch);
|
||||||
|
|
||||||
|
return mappingTree;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Failed to read mappings", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isRecord(StructClass structClass) {
|
||||||
|
return (structClass.getAccessFlags() & ACC_RECORD) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isStatic(StructField structField) {
|
||||||
|
return (structField.getAccessFlags() & ACC_STATIC) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2021 FabricMC
|
* Copyright (c) 2019-2023 FabricMC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.fabricmc.loom.decompilers.fernflower;
|
package net.fabricmc.loom.decompilers.vineflower;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -33,34 +33,36 @@ import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
|
|||||||
import org.jetbrains.java.decompiler.main.extern.IResultSaver;
|
import org.jetbrains.java.decompiler.main.extern.IResultSaver;
|
||||||
|
|
||||||
import net.fabricmc.fernflower.api.IFabricJavadocProvider;
|
import net.fabricmc.fernflower.api.IFabricJavadocProvider;
|
||||||
import net.fabricmc.loom.api.decompilers.DecompilationMetadata;
|
import net.fabricmc.loom.decompilers.LoomInternalDecompiler;
|
||||||
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
|
|
||||||
|
|
||||||
public final class FabricFernFlowerDecompiler implements LoomDecompiler {
|
public final class VineflowerDecompiler implements LoomInternalDecompiler {
|
||||||
@Override
|
@Override
|
||||||
public void decompile(Path compiledJar, Path sourcesDestination, Path linemapDestination, DecompilationMetadata metaData) {
|
public void decompile(Context context) {
|
||||||
|
Path sourcesDestination = context.sourcesDestination();
|
||||||
|
Path linemapDestination = context.linemapDestination();
|
||||||
|
|
||||||
final Map<String, Object> options = new HashMap<>(
|
final Map<String, Object> options = new HashMap<>(
|
||||||
Map.of(
|
Map.of(
|
||||||
IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES, "1",
|
IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES, "1",
|
||||||
IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1",
|
IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1",
|
||||||
IFernflowerPreferences.REMOVE_SYNTHETIC, "1",
|
IFernflowerPreferences.REMOVE_SYNTHETIC, "1",
|
||||||
IFernflowerPreferences.LOG_LEVEL, "trace",
|
IFernflowerPreferences.LOG_LEVEL, "trace",
|
||||||
IFernflowerPreferences.THREADS, String.valueOf(metaData.numberOfThreads()),
|
IFernflowerPreferences.THREADS, String.valueOf(context.numberOfThreads()),
|
||||||
IFernflowerPreferences.INDENT_STRING, "\t",
|
IFernflowerPreferences.INDENT_STRING, "\t",
|
||||||
IFabricJavadocProvider.PROPERTY_NAME, new TinyJavadocProvider(metaData.javaDocs().toFile())
|
IFabricJavadocProvider.PROPERTY_NAME, new TinyJavadocProvider(context.javaDocs().toFile())
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
options.putAll(metaData.options());
|
options.putAll(context.options());
|
||||||
|
|
||||||
IResultSaver saver = new ThreadSafeResultSaver(sourcesDestination::toFile, linemapDestination::toFile);
|
IResultSaver saver = new ThreadSafeResultSaver(sourcesDestination::toFile, linemapDestination::toFile);
|
||||||
Fernflower ff = new Fernflower(FernFlowerUtils::getBytecode, saver, options, new FernflowerLogger(metaData.logger()));
|
Fernflower ff = new Fernflower(saver, options, new VineflowerLogger(context.logger()));
|
||||||
|
|
||||||
for (Path library : metaData.libraries()) {
|
for (Path library : context.libraries()) {
|
||||||
ff.addLibrary(library.toFile());
|
ff.addLibrary(library.toFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
ff.addSource(compiledJar.toFile());
|
ff.addSource(context.compiledJar().toFile());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ff.decompileContext();
|
ff.decompileContext();
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2023 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.decompilers.vineflower;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.decompilers.LoomInternalDecompiler;
|
||||||
|
|
||||||
|
public class VineflowerLogger extends IFernflowerLogger {
|
||||||
|
private final LoomInternalDecompiler.Logger logger;
|
||||||
|
|
||||||
|
public VineflowerLogger(LoomInternalDecompiler.Logger logger) {
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeMessage(String message, Severity severity) {
|
||||||
|
if (severity.ordinal() < Severity.ERROR.ordinal()) return;
|
||||||
|
|
||||||
|
System.err.println(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeMessage(String message, Severity severity, Throwable t) {
|
||||||
|
if (severity.ordinal() < Severity.ERROR.ordinal()) return;
|
||||||
|
|
||||||
|
writeMessage(message, severity);
|
||||||
|
t.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void write(String data) {
|
||||||
|
try {
|
||||||
|
logger.accept(data);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Failed to log", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startReadingClass(String className) {
|
||||||
|
write("Decompiling " + className);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startClass(String className) {
|
||||||
|
write("Decompiling " + className);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startWriteClass(String className) {
|
||||||
|
// Nope
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startMethod(String methodName) {
|
||||||
|
// Nope
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endMethod() {
|
||||||
|
// Nope
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -99,7 +99,7 @@ public class LoomGradlePlugin implements BootstrappedPlugin {
|
|||||||
|
|
||||||
// Setup extensions
|
// Setup extensions
|
||||||
project.getExtensions().create(LoomGradleExtensionAPI.class, "loom", LoomGradleExtensionImpl.class, project, LoomFiles.create(project));
|
project.getExtensions().create(LoomGradleExtensionAPI.class, "loom", LoomGradleExtensionImpl.class, project, LoomFiles.create(project));
|
||||||
project.getExtensions().create("fabricApi", FabricApiExtension.class, project);
|
project.getExtensions().create("fabricApi", FabricApiExtension.class);
|
||||||
|
|
||||||
for (Class<? extends Runnable> jobClass : SETUP_JOBS) {
|
for (Class<? extends Runnable> jobClass : SETUP_JOBS) {
|
||||||
project.getObjects().newInstance(jobClass).run();
|
project.getObjects().newInstance(jobClass).run();
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import org.gradle.api.file.RegularFileProperty;
|
|||||||
import org.gradle.api.provider.ListProperty;
|
import org.gradle.api.provider.ListProperty;
|
||||||
import org.gradle.api.provider.Property;
|
import org.gradle.api.provider.Property;
|
||||||
import org.gradle.api.provider.Provider;
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.gradle.api.provider.SetProperty;
|
||||||
import org.gradle.api.publish.maven.MavenPublication;
|
import org.gradle.api.publish.maven.MavenPublication;
|
||||||
import org.gradle.api.tasks.SourceSet;
|
import org.gradle.api.tasks.SourceSet;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
@@ -133,6 +134,8 @@ public interface LoomGradleExtensionAPI {
|
|||||||
|
|
||||||
Property<String> getCustomMinecraftManifest();
|
Property<String> getCustomMinecraftManifest();
|
||||||
|
|
||||||
|
SetProperty<String> getKnownIndyBsms();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disables the deprecated POM generation for a publication.
|
* Disables the deprecated POM generation for a publication.
|
||||||
* This is useful if you want to suppress deprecation warnings when you're not using software components.
|
* This is useful if you want to suppress deprecation warnings when you're not using software components.
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
|||||||
import net.fabricmc.loom.extension.MixinExtension;
|
import net.fabricmc.loom.extension.MixinExtension;
|
||||||
import net.fabricmc.loom.task.PrepareJarRemapTask;
|
import net.fabricmc.loom.task.PrepareJarRemapTask;
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
|
import net.fabricmc.loom.util.LoomVersions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normally javac invokes annotation processors, but when the scala or kapt plugin are installed they will want to invoke
|
* Normally javac invokes annotation processors, but when the scala or kapt plugin are installed they will want to invoke
|
||||||
@@ -150,7 +151,7 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
|
|||||||
|
|
||||||
// Add Mixin and mixin extensions (fabric-mixin-compile-extensions pulls mixin itself too)
|
// Add Mixin and mixin extensions (fabric-mixin-compile-extensions pulls mixin itself too)
|
||||||
project.getDependencies().add(processorConfig.getName(),
|
project.getDependencies().add(processorConfig.getName(),
|
||||||
Constants.Dependencies.MIXIN_COMPILE_EXTENSIONS + Constants.Dependencies.Versions.MIXIN_COMPILE_EXTENSIONS);
|
LoomVersions.MIXIN_COMPILE_EXTENSIONS.mavenNotation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,11 @@ package net.fabricmc.loom.configuration;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
|
||||||
@@ -41,25 +43,29 @@ import org.w3c.dom.NodeList;
|
|||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.util.download.DownloadException;
|
import net.fabricmc.loom.util.download.DownloadException;
|
||||||
|
|
||||||
public class FabricApiExtension {
|
public abstract class FabricApiExtension {
|
||||||
private final Project project;
|
@Inject
|
||||||
|
public abstract Project getProject();
|
||||||
public FabricApiExtension(Project project) {
|
|
||||||
this.project = project;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final HashMap<String, Map<String, String>> moduleVersionCache = new HashMap<>();
|
private static final HashMap<String, Map<String, String>> moduleVersionCache = new HashMap<>();
|
||||||
|
private static final HashMap<String, Map<String, String>> deprecatedModuleVersionCache = new HashMap<>();
|
||||||
|
|
||||||
public Dependency module(String moduleName, String fabricApiVersion) {
|
public Dependency module(String moduleName, String fabricApiVersion) {
|
||||||
return project.getDependencies()
|
return getProject().getDependencies()
|
||||||
.create(getDependencyNotation(moduleName, fabricApiVersion));
|
.create(getDependencyNotation(moduleName, fabricApiVersion));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String moduleVersion(String moduleName, String fabricApiVersion) {
|
public String moduleVersion(String moduleName, String fabricApiVersion) {
|
||||||
String moduleVersion = moduleVersionCache
|
String moduleVersion = moduleVersionCache
|
||||||
.computeIfAbsent(fabricApiVersion, this::populateModuleVersionMap)
|
.computeIfAbsent(fabricApiVersion, this::getApiModuleVersions)
|
||||||
.get(moduleName);
|
.get(moduleName);
|
||||||
|
|
||||||
|
if (moduleVersion == null) {
|
||||||
|
moduleVersion = deprecatedModuleVersionCache
|
||||||
|
.computeIfAbsent(fabricApiVersion, this::getDeprecatedApiModuleVersions)
|
||||||
|
.get(moduleName);
|
||||||
|
}
|
||||||
|
|
||||||
if (moduleVersion == null) {
|
if (moduleVersion == null) {
|
||||||
throw new RuntimeException("Failed to find module version for module: " + moduleName);
|
throw new RuntimeException("Failed to find module version for module: " + moduleName);
|
||||||
}
|
}
|
||||||
@@ -71,9 +77,24 @@ public class FabricApiExtension {
|
|||||||
return String.format("net.fabricmc.fabric-api:%s:%s", moduleName, moduleVersion(moduleName, fabricApiVersion));
|
return String.format("net.fabricmc.fabric-api:%s:%s", moduleName, moduleVersion(moduleName, fabricApiVersion));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, String> populateModuleVersionMap(String fabricApiVersion) {
|
private Map<String, String> getApiModuleVersions(String fabricApiVersion) {
|
||||||
File pomFile = getApiMavenPom(fabricApiVersion);
|
try {
|
||||||
|
return populateModuleVersionMap(getApiMavenPom(fabricApiVersion));
|
||||||
|
} catch (PomNotFoundException e) {
|
||||||
|
throw new RuntimeException("Could not find fabric-api version: " + fabricApiVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> getDeprecatedApiModuleVersions(String fabricApiVersion) {
|
||||||
|
try {
|
||||||
|
return populateModuleVersionMap(getDeprecatedApiMavenPom(fabricApiVersion));
|
||||||
|
} catch (PomNotFoundException e) {
|
||||||
|
// Not all fabric-api versions have deprecated modules, return an empty map to cache this fact.
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> populateModuleVersionMap(File pomFile) {
|
||||||
try {
|
try {
|
||||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
||||||
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
||||||
@@ -101,27 +122,36 @@ public class FabricApiExtension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private File getApiMavenPom(String fabricApiVersion) {
|
private File getApiMavenPom(String fabricApiVersion) throws PomNotFoundException {
|
||||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
return getPom("fabric-api", fabricApiVersion);
|
||||||
|
}
|
||||||
|
|
||||||
File mavenPom = new File(extension.getFiles().getUserCache(), "fabric-api/" + fabricApiVersion + ".pom");
|
private File getDeprecatedApiMavenPom(String fabricApiVersion) throws PomNotFoundException {
|
||||||
|
return getPom("fabric-api-deprecated", fabricApiVersion);
|
||||||
|
}
|
||||||
|
|
||||||
if (project.getGradle().getStartParameter().isOffline()) {
|
private File getPom(String name, String version) throws PomNotFoundException {
|
||||||
if (!mavenPom.exists()) {
|
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
||||||
throw new RuntimeException("Cannot retrieve fabric-api pom due to being offline");
|
final var mavenPom = new File(extension.getFiles().getUserCache(), "fabric-api/%s-%s.pom".formatted(name, version));
|
||||||
}
|
|
||||||
|
|
||||||
return mavenPom;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
extension.download(String.format("https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api/%1$s/fabric-api-%1$s.pom", fabricApiVersion))
|
extension.download(String.format("https://maven.fabricmc.net/net/fabricmc/fabric-api/%2$s/%1$s/%2$s-%1$s.pom", version, name))
|
||||||
.defaultCache()
|
.defaultCache()
|
||||||
.downloadPath(mavenPom.toPath());
|
.downloadPath(mavenPom.toPath());
|
||||||
} catch (DownloadException e) {
|
} catch (DownloadException e) {
|
||||||
throw new UncheckedIOException("Failed to download maven info for " + fabricApiVersion, e);
|
if (e.getStatusCode() == 404) {
|
||||||
|
throw new PomNotFoundException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UncheckedIOException("Failed to download maven info to " + mavenPom.getName(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mavenPom;
|
return mavenPom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class PomNotFoundException extends Exception {
|
||||||
|
PomNotFoundException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,16 @@
|
|||||||
|
|
||||||
package net.fabricmc.loom.configuration;
|
package net.fabricmc.loom.configuration;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
import org.gradle.api.artifacts.Configuration;
|
import org.gradle.api.artifacts.Configuration;
|
||||||
import org.gradle.api.artifacts.ExternalModuleDependency;
|
import org.gradle.api.artifacts.ExternalModuleDependency;
|
||||||
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
|
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
|
||||||
|
import org.gradle.api.plugins.JavaPlugin;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.LoomRepositoryPlugin;
|
import net.fabricmc.loom.LoomRepositoryPlugin;
|
||||||
@@ -36,6 +41,8 @@ import net.fabricmc.loom.configuration.ide.idea.IdeaUtils;
|
|||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
|
|
||||||
public record InstallerData(String version, JsonObject installerJson) {
|
public record InstallerData(String version, JsonObject installerJson) {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(InstallerData.class);
|
||||||
|
|
||||||
public void applyToProject(Project project) {
|
public void applyToProject(Project project) {
|
||||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||||
|
|
||||||
@@ -45,35 +52,61 @@ public record InstallerData(String version, JsonObject installerJson) {
|
|||||||
|
|
||||||
extension.setInstallerData(this);
|
extension.setInstallerData(this);
|
||||||
|
|
||||||
JsonObject libraries = installerJson.get("libraries").getAsJsonObject();
|
final JsonObject libraries = installerJson.get("libraries").getAsJsonObject();
|
||||||
Configuration loaderDepsConfig = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES);
|
|
||||||
Configuration apDepsConfig = project.getConfigurations().getByName("annotationProcessor");
|
|
||||||
|
|
||||||
libraries.get("common").getAsJsonArray().forEach(jsonElement -> {
|
applyDependendencies(libraries.get("common").getAsJsonArray(), project);
|
||||||
String name = jsonElement.getAsJsonObject().get("name").getAsString();
|
|
||||||
project.getLogger().debug("Adding dependency ({}) from installer JSON", name);
|
// Apply development dependencies if they exist.
|
||||||
|
if (libraries.has("development")) {
|
||||||
|
applyDependendencies(libraries.get("development").getAsJsonArray(), project);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyDependendencies(JsonArray jsonArray, Project project) {
|
||||||
|
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||||
|
Configuration loaderDepsConfig = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES);
|
||||||
|
Configuration annotationProcessor = project.getConfigurations().getByName(JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME);
|
||||||
|
|
||||||
|
for (JsonElement jsonElement : jsonArray) {
|
||||||
|
final JsonObject jsonObject = jsonElement.getAsJsonObject();
|
||||||
|
final String name = jsonObject.get("name").getAsString();
|
||||||
|
|
||||||
|
LOGGER.debug("Adding dependency ({}) from installer JSON", name);
|
||||||
|
|
||||||
ExternalModuleDependency modDep = (ExternalModuleDependency) project.getDependencies().create(name);
|
ExternalModuleDependency modDep = (ExternalModuleDependency) project.getDependencies().create(name);
|
||||||
modDep.setTransitive(false);
|
modDep.setTransitive(false); // Match the launcher in not being transitive
|
||||||
loaderDepsConfig.getDependencies().add(modDep);
|
loaderDepsConfig.getDependencies().add(modDep);
|
||||||
|
|
||||||
// TODO: work around until https://github.com/FabricMC/Mixin/pull/60 and https://github.com/FabricMC/fabric-mixin-compile-extensions/issues/14 is fixed.
|
// Work around https://github.com/FabricMC/Mixin/pull/60 and https://github.com/FabricMC/fabric-mixin-compile-extensions/issues/14.
|
||||||
if (!IdeaUtils.isIdeaSync() && extension.getMixin().getUseLegacyMixinAp().get()) {
|
if (!IdeaUtils.isIdeaSync() && extension.getMixin().getUseLegacyMixinAp().get()) {
|
||||||
apDepsConfig.getDependencies().add(modDep);
|
annotationProcessor.getDependencies().add(modDep);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If user choose to use dependencyResolutionManagement, then they should declare
|
// If user choose to use dependencyResolutionManagement, then they should declare
|
||||||
// these repositories manually in the settings file.
|
// these repositories manually in the settings file.
|
||||||
if (jsonElement.getAsJsonObject().has("url") && !project.getGradle().getPlugins().hasPlugin(LoomRepositoryPlugin.class)) {
|
if (project.getGradle().getPlugins().hasPlugin(LoomRepositoryPlugin.class)) {
|
||||||
String url = jsonElement.getAsJsonObject().get("url").getAsString();
|
continue;
|
||||||
long count = project.getRepositories().stream().filter(artifactRepository -> artifactRepository instanceof MavenArtifactRepository)
|
|
||||||
.map(artifactRepository -> (MavenArtifactRepository) artifactRepository)
|
|
||||||
.filter(mavenArtifactRepository -> mavenArtifactRepository.getUrl().toString().equalsIgnoreCase(url)).count();
|
|
||||||
|
|
||||||
if (count == 0) {
|
|
||||||
project.getRepositories().maven(mavenArtifactRepository -> mavenArtifactRepository.setUrl(jsonElement.getAsJsonObject().get("url").getAsString()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
addRepository(jsonObject, project);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRepository(JsonObject jsonObject, Project project) {
|
||||||
|
if (!jsonObject.has("url")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String url = jsonObject.get("url").getAsString();
|
||||||
|
final boolean isPresent = project.getRepositories().stream()
|
||||||
|
.filter(artifactRepository -> artifactRepository instanceof MavenArtifactRepository)
|
||||||
|
.map(artifactRepository -> (MavenArtifactRepository) artifactRepository)
|
||||||
|
.anyMatch(mavenArtifactRepository -> mavenArtifactRepository.getUrl().toString().equalsIgnoreCase(url));
|
||||||
|
|
||||||
|
if (isPresent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
project.getRepositories().maven(mavenArtifactRepository -> mavenArtifactRepository.setUrl(jsonObject.get("url").getAsString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import org.gradle.api.plugins.JavaPlugin;
|
|||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
|
import net.fabricmc.loom.util.LoomVersions;
|
||||||
import net.fabricmc.loom.util.gradle.GradleUtils;
|
import net.fabricmc.loom.util.gradle.GradleUtils;
|
||||||
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||||
|
|
||||||
@@ -106,10 +107,10 @@ public abstract class LoomConfigurations implements Runnable {
|
|||||||
extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MINECRAFT_RUNTIME_LIBRARIES);
|
extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MINECRAFT_RUNTIME_LIBRARIES);
|
||||||
|
|
||||||
// Add the dev time dependencies
|
// Add the dev time dependencies
|
||||||
getDependencies().add(Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, Constants.Dependencies.DEV_LAUNCH_INJECTOR + Constants.Dependencies.Versions.DEV_LAUNCH_INJECTOR);
|
getDependencies().add(Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, LoomVersions.DEV_LAUNCH_INJECTOR.mavenNotation());
|
||||||
getDependencies().add(Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, Constants.Dependencies.TERMINAL_CONSOLE_APPENDER + Constants.Dependencies.Versions.TERMINAL_CONSOLE_APPENDER);
|
getDependencies().add(Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, LoomVersions.TERMINAL_CONSOLE_APPENDER.mavenNotation());
|
||||||
getDependencies().add(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME, Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS);
|
getDependencies().add(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME, LoomVersions.JETBRAINS_ANNOTATIONS.mavenNotation());
|
||||||
getDependencies().add(JavaPlugin.TEST_COMPILE_ONLY_CONFIGURATION_NAME, Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS);
|
getDependencies().add(JavaPlugin.TEST_COMPILE_ONLY_CONFIGURATION_NAME, LoomVersions.JETBRAINS_ANNOTATIONS.mavenNotation());
|
||||||
|
|
||||||
GradleUtils.afterSuccessfulEvaluation(getProject(), () -> {
|
GradleUtils.afterSuccessfulEvaluation(getProject(), () -> {
|
||||||
if (extension.shouldGenerateSrgTiny()) {
|
if (extension.shouldGenerateSrgTiny()) {
|
||||||
|
|||||||
@@ -170,9 +170,10 @@ public class ModProcessor {
|
|||||||
MemoryMappingTree mappings = mappingConfiguration.getMappingsService(serviceManager, srg).getMappingTree();
|
MemoryMappingTree mappings = mappingConfiguration.getMappingsService(serviceManager, srg).getMappingTree();
|
||||||
LoggerFilter.replaceSystemOut();
|
LoggerFilter.replaceSystemOut();
|
||||||
TinyRemapper.Builder builder = TinyRemapper.newRemapper()
|
TinyRemapper.Builder builder = TinyRemapper.newRemapper()
|
||||||
|
.withKnownIndyBsm(extension.getKnownIndyBsms().get())
|
||||||
|
.withMappings(TinyRemapperHelper.create(mappingConfiguration.getMappingsService(serviceManager).getMappingTree(), fromM, toM, false))
|
||||||
.logger(project.getLogger()::lifecycle)
|
.logger(project.getLogger()::lifecycle)
|
||||||
.logUnknownInvokeDynamic(false)
|
.logUnknownInvokeDynamic(false)
|
||||||
.withMappings(TinyRemapperHelper.create(mappings, fromM, toM, false))
|
|
||||||
.renameInvalidLocals(false)
|
.renameInvalidLocals(false)
|
||||||
.extraAnalyzeVisitor(AccessWidenerAnalyzeVisitorProvider.createFromMods(fromM, remapList, extension.getPlatform().get()));
|
.extraAnalyzeVisitor(AccessWidenerAnalyzeVisitorProvider.createFromMods(fromM, remapList, extension.getPlatform().get()));
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import java.util.function.Predicate;
|
|||||||
import net.fabricmc.loom.configuration.providers.minecraft.library.Library;
|
import net.fabricmc.loom.configuration.providers.minecraft.library.Library;
|
||||||
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryContext;
|
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryContext;
|
||||||
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessor;
|
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessor;
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.LoomVersions;
|
||||||
import net.fabricmc.loom.util.Platform;
|
import net.fabricmc.loom.util.Platform;
|
||||||
|
|
||||||
public class LoomNativeSupportLibraryProcessor extends LibraryProcessor {
|
public class LoomNativeSupportLibraryProcessor extends LibraryProcessor {
|
||||||
@@ -56,7 +56,7 @@ public class LoomNativeSupportLibraryProcessor extends LibraryProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Predicate<Library> apply(Consumer<Library> dependencyConsumer) {
|
public Predicate<Library> apply(Consumer<Library> dependencyConsumer) {
|
||||||
dependencyConsumer.accept(Library.fromMaven(Constants.Dependencies.NATIVE_SUPPORT + Constants.Dependencies.Versions.NATIVE_SUPPORT_VERSION, Library.Target.LOCAL_MOD));
|
dependencyConsumer.accept(Library.fromMaven(LoomVersions.NATIVE_SUPPORT.mavenNotation(), Library.Target.LOCAL_MOD));
|
||||||
return ALLOW_ALL;
|
return ALLOW_ALL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018-2020 FabricMC
|
* Copyright (c) 2018-2023 FabricMC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -24,14 +24,27 @@
|
|||||||
|
|
||||||
package net.fabricmc.loom.decompilers;
|
package net.fabricmc.loom.decompilers;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.gradle.api.NamedDomainObjectProvider;
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.artifacts.Configuration;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
|
import net.fabricmc.loom.api.decompilers.DecompilationMetadata;
|
||||||
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
|
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
|
||||||
import net.fabricmc.loom.decompilers.cfr.LoomCFRDecompiler;
|
import net.fabricmc.loom.decompilers.cfr.LoomCFRDecompiler;
|
||||||
import net.fabricmc.loom.decompilers.fernflower.FabricFernFlowerDecompiler;
|
import net.fabricmc.loom.decompilers.fernflower.FabricFernFlowerDecompiler;
|
||||||
|
import net.fabricmc.loom.decompilers.vineflower.VineflowerDecompiler;
|
||||||
|
import net.fabricmc.loom.util.LoomVersions;
|
||||||
|
import net.fabricmc.loom.util.ZipUtils;
|
||||||
|
|
||||||
public abstract class DecompilerConfiguration implements Runnable {
|
public abstract class DecompilerConfiguration implements Runnable {
|
||||||
@Inject
|
@Inject
|
||||||
@@ -39,11 +52,118 @@ public abstract class DecompilerConfiguration implements Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
registerDecompiler(getProject(), "fernFlower", FabricFernFlowerDecompiler.class);
|
var fernflowerConfiguration = createConfiguration("fernflower", LoomVersions.FERNFLOWER);
|
||||||
registerDecompiler(getProject(), "cfr", LoomCFRDecompiler.class);
|
var cfrConfiguration = createConfiguration("cfr", LoomVersions.CFR);
|
||||||
|
var vineflowerConfiguration = createConfiguration("vineflower", LoomVersions.VINEFLOWER);
|
||||||
|
|
||||||
|
registerDecompiler(getProject(), "fernFlower", BuiltinFernflower.class, fernflowerConfiguration);
|
||||||
|
registerDecompiler(getProject(), "cfr", BuiltinCfr.class, cfrConfiguration);
|
||||||
|
registerDecompiler(getProject(), "vineflower", BuiltinVineflower.class, vineflowerConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerDecompiler(Project project, String name, Class<? extends LoomDecompiler> decompilerClass) {
|
private NamedDomainObjectProvider<Configuration> createConfiguration(String name, LoomVersions version) {
|
||||||
LoomGradleExtension.get(project).getDecompilerOptions().register(name, options -> options.getDecompilerClassName().set(decompilerClass.getName()));
|
final String configurationName = name + "DecompilerClasspath";
|
||||||
|
NamedDomainObjectProvider<Configuration> configuration = getProject().getConfigurations().register(configurationName);
|
||||||
|
getProject().getDependencies().add(configurationName, version.mavenNotation());
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerDecompiler(Project project, String name, Class<? extends LoomDecompiler> decompilerClass, NamedDomainObjectProvider<Configuration> configuration) {
|
||||||
|
LoomGradleExtension.get(project).getDecompilerOptions().register(name, options -> {
|
||||||
|
options.getDecompilerClassName().set(decompilerClass.getName());
|
||||||
|
options.getClasspath().from(configuration);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to wrap the internal API with the public API.
|
||||||
|
// This is needed as the sourceset containing fabric's decompilers do not have access to loom classes.
|
||||||
|
private abstract static sealed class BuiltinDecompiler implements LoomDecompiler permits BuiltinFernflower, BuiltinCfr, BuiltinVineflower {
|
||||||
|
private final LoomInternalDecompiler internalDecompiler;
|
||||||
|
|
||||||
|
BuiltinDecompiler(LoomInternalDecompiler internalDecompiler) {
|
||||||
|
this.internalDecompiler = internalDecompiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decompile(Path compiledJar, Path sourcesDestination, Path linemapDestination, DecompilationMetadata metaData) {
|
||||||
|
final Logger slf4jLogger = LoggerFactory.getLogger(internalDecompiler.getClass());
|
||||||
|
|
||||||
|
final var logger = new LoomInternalDecompiler.Logger() {
|
||||||
|
@Override
|
||||||
|
public void accept(String data) throws IOException {
|
||||||
|
metaData.logger().accept(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String msg) {
|
||||||
|
slf4jLogger.error(msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
internalDecompiler.decompile(new LoomInternalDecompiler.Context() {
|
||||||
|
@Override
|
||||||
|
public Path compiledJar() {
|
||||||
|
return compiledJar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path sourcesDestination() {
|
||||||
|
return sourcesDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path linemapDestination() {
|
||||||
|
return linemapDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int numberOfThreads() {
|
||||||
|
return metaData.numberOfThreads();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Path javaDocs() {
|
||||||
|
return metaData.javaDocs();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Path> libraries() {
|
||||||
|
return metaData.libraries();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LoomInternalDecompiler.Logger logger() {
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> options() {
|
||||||
|
return metaData.options();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] unpackZip(Path zip, String path) throws IOException {
|
||||||
|
return ZipUtils.unpack(zip, path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class BuiltinFernflower extends BuiltinDecompiler {
|
||||||
|
public BuiltinFernflower() {
|
||||||
|
super(new FabricFernFlowerDecompiler());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class BuiltinCfr extends BuiltinDecompiler {
|
||||||
|
public BuiltinCfr() {
|
||||||
|
super(new LoomCFRDecompiler());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class BuiltinVineflower extends BuiltinDecompiler {
|
||||||
|
public BuiltinVineflower() {
|
||||||
|
super(new VineflowerDecompiler());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import com.google.common.base.Suppliers;
|
import com.google.common.base.Suppliers;
|
||||||
@@ -43,6 +44,7 @@ import org.gradle.api.file.RegularFileProperty;
|
|||||||
import org.gradle.api.provider.ListProperty;
|
import org.gradle.api.provider.ListProperty;
|
||||||
import org.gradle.api.provider.Property;
|
import org.gradle.api.provider.Property;
|
||||||
import org.gradle.api.provider.Provider;
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.gradle.api.provider.SetProperty;
|
||||||
import org.gradle.api.publish.maven.MavenPublication;
|
import org.gradle.api.publish.maven.MavenPublication;
|
||||||
import org.gradle.api.tasks.SourceSet;
|
import org.gradle.api.tasks.SourceSet;
|
||||||
|
|
||||||
@@ -85,6 +87,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
|||||||
protected final ConfigurableFileCollection log4jConfigs;
|
protected final ConfigurableFileCollection log4jConfigs;
|
||||||
protected final RegularFileProperty accessWidener;
|
protected final RegularFileProperty accessWidener;
|
||||||
protected final Property<String> customManifest;
|
protected final Property<String> customManifest;
|
||||||
|
protected final SetProperty<String> knownIndyBsms;
|
||||||
protected final Property<Boolean> transitiveAccessWideners;
|
protected final Property<Boolean> transitiveAccessWideners;
|
||||||
protected final Property<Boolean> modProvidedJavadoc;
|
protected final Property<Boolean> modProvidedJavadoc;
|
||||||
protected final Property<String> intermediary;
|
protected final Property<String> intermediary;
|
||||||
@@ -121,6 +124,12 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
|||||||
this.log4jConfigs = project.files(directories.getDefaultLog4jConfigFile());
|
this.log4jConfigs = project.files(directories.getDefaultLog4jConfigFile());
|
||||||
this.accessWidener = project.getObjects().fileProperty();
|
this.accessWidener = project.getObjects().fileProperty();
|
||||||
this.customManifest = project.getObjects().property(String.class);
|
this.customManifest = project.getObjects().property(String.class);
|
||||||
|
this.knownIndyBsms = project.getObjects().setProperty(String.class).convention(Set.of(
|
||||||
|
"java/lang/invoke/StringConcatFactory",
|
||||||
|
"java/lang/runtime/ObjectMethods",
|
||||||
|
"org/codehaus/groovy/vmplugin/v8/IndyInterface"
|
||||||
|
));
|
||||||
|
this.knownIndyBsms.finalizeValueOnRead();
|
||||||
this.transitiveAccessWideners = project.getObjects().property(Boolean.class)
|
this.transitiveAccessWideners = project.getObjects().property(Boolean.class)
|
||||||
.convention(true);
|
.convention(true);
|
||||||
this.transitiveAccessWideners.finalizeValueOnRead();
|
this.transitiveAccessWideners.finalizeValueOnRead();
|
||||||
@@ -275,6 +284,11 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
|||||||
return customManifest;
|
return customManifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SetProperty<String> getKnownIndyBsms() {
|
||||||
|
return knownIndyBsms;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getModVersion() {
|
public String getModVersion() {
|
||||||
return versionParser.getModVersion();
|
return versionParser.getModVersion();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016-2022 FabricMC
|
* Copyright (c) 2023 FabricMC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -22,23 +22,16 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.fabricmc.loom.decompilers.fernflower;
|
package net.fabricmc.loom.kotlin.remapping;
|
||||||
|
|
||||||
import java.io.File;
|
import kotlin.Metadata;
|
||||||
import java.io.IOException;
|
import kotlinx.metadata.jvm.KotlinClassMetadata;
|
||||||
|
|
||||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
/**
|
||||||
|
* Similar story to JvmExtensionWrapper, lets abuse the fact that Java can call "internal" Kotlin APIs without reflection :).
|
||||||
import net.fabricmc.loom.util.ZipUtils;
|
*/
|
||||||
|
public record KotlinClassMetadataWrapper(KotlinClassMetadata metadata) {
|
||||||
public class FernFlowerUtils {
|
public Metadata getAnnotationData() {
|
||||||
public static byte[] getBytecode(String externalPath, String internalPath) throws IOException {
|
return metadata.getAnnotationData$kotlinx_metadata_jvm();
|
||||||
File file = new File(externalPath);
|
|
||||||
|
|
||||||
if (internalPath == null) {
|
|
||||||
return InterpreterUtil.getBytes(file);
|
|
||||||
} else {
|
|
||||||
return ZipUtils.unpack(file.toPath(), internalPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,6 +30,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -53,6 +54,7 @@ import org.gradle.api.tasks.InputFiles;
|
|||||||
import org.gradle.api.tasks.Internal;
|
import org.gradle.api.tasks.Internal;
|
||||||
import org.gradle.api.tasks.Optional;
|
import org.gradle.api.tasks.Optional;
|
||||||
import org.gradle.api.tasks.SourceSet;
|
import org.gradle.api.tasks.SourceSet;
|
||||||
|
import org.gradle.api.tasks.bundling.ZipEntryCompression;
|
||||||
import org.gradle.build.event.BuildEventsListenerRegistry;
|
import org.gradle.build.event.BuildEventsListenerRegistry;
|
||||||
import org.gradle.jvm.tasks.Jar;
|
import org.gradle.jvm.tasks.Jar;
|
||||||
import org.gradle.workers.WorkAction;
|
import org.gradle.workers.WorkAction;
|
||||||
@@ -74,6 +76,7 @@ public abstract class AbstractRemapJarTask extends Jar {
|
|||||||
public static final String MANIFEST_NAMESPACE_KEY = "Fabric-Mapping-Namespace";
|
public static final String MANIFEST_NAMESPACE_KEY = "Fabric-Mapping-Namespace";
|
||||||
public static final String MANIFEST_SPLIT_ENV_KEY = "Fabric-Loom-Split-Environment";
|
public static final String MANIFEST_SPLIT_ENV_KEY = "Fabric-Loom-Split-Environment";
|
||||||
public static final String MANIFEST_CLIENT_ENTRIES_KEY = "Fabric-Loom-Client-Only-Entries";
|
public static final String MANIFEST_CLIENT_ENTRIES_KEY = "Fabric-Loom-Client-Only-Entries";
|
||||||
|
public static final String MANIFEST_JAR_TYPE_KEY = "Fabric-Jar-Type";
|
||||||
public static final Attributes.Name MANIFEST_SPLIT_ENV_NAME = new Attributes.Name(MANIFEST_SPLIT_ENV_KEY);
|
public static final Attributes.Name MANIFEST_SPLIT_ENV_NAME = new Attributes.Name(MANIFEST_SPLIT_ENV_KEY);
|
||||||
public static final Attributes.Name MANIFEST_CLIENT_ENTRIES_NAME = new Attributes.Name(MANIFEST_CLIENT_ENTRIES_KEY);
|
public static final Attributes.Name MANIFEST_CLIENT_ENTRIES_NAME = new Attributes.Name(MANIFEST_CLIENT_ENTRIES_KEY);
|
||||||
|
|
||||||
@@ -111,6 +114,11 @@ public abstract class AbstractRemapJarTask extends Jar {
|
|||||||
@Optional
|
@Optional
|
||||||
public abstract Property<String> getClientOnlySourceSetName();
|
public abstract Property<String> getClientOnlySourceSetName();
|
||||||
|
|
||||||
|
@Input
|
||||||
|
@Optional
|
||||||
|
@ApiStatus.Internal
|
||||||
|
public abstract Property<String> getJarType();
|
||||||
|
|
||||||
private final Provider<JarManifestService> jarManifestServiceProvider;
|
private final Provider<JarManifestService> jarManifestServiceProvider;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -119,6 +127,7 @@ public abstract class AbstractRemapJarTask extends Jar {
|
|||||||
getTargetNamespace().convention(IntermediaryNamespaces.intermediary(getProject())).finalizeValueOnRead();
|
getTargetNamespace().convention(IntermediaryNamespaces.intermediary(getProject())).finalizeValueOnRead();
|
||||||
getRemapperIsolation().convention(true).finalizeValueOnRead();
|
getRemapperIsolation().convention(true).finalizeValueOnRead();
|
||||||
getIncludesClientOnlyClasses().convention(false).finalizeValueOnRead();
|
getIncludesClientOnlyClasses().convention(false).finalizeValueOnRead();
|
||||||
|
getJarType().finalizeValueOnRead();
|
||||||
|
|
||||||
jarManifestServiceProvider = JarManifestService.get(getProject());
|
jarManifestServiceProvider = JarManifestService.get(getProject());
|
||||||
usesService(jarManifestServiceProvider);
|
usesService(jarManifestServiceProvider);
|
||||||
@@ -138,14 +147,20 @@ public abstract class AbstractRemapJarTask extends Jar {
|
|||||||
params.getArchiveReproducibleFileOrder().set(isReproducibleFileOrder());
|
params.getArchiveReproducibleFileOrder().set(isReproducibleFileOrder());
|
||||||
|
|
||||||
params.getJarManifestService().set(jarManifestServiceProvider);
|
params.getJarManifestService().set(jarManifestServiceProvider);
|
||||||
|
params.getEntryCompression().set(getEntryCompression());
|
||||||
|
|
||||||
if (getIncludesClientOnlyClasses().get()) {
|
if (getIncludesClientOnlyClasses().get()) {
|
||||||
final List<String> clientOnlyEntries = new ArrayList<>(getClientOnlyEntries(getClientSourceSet()));
|
final List<String> clientOnlyEntries = new ArrayList<>(getClientOnlyEntries(getClientSourceSet()));
|
||||||
clientOnlyEntries.addAll(getAdditionalClientOnlyEntries().get());
|
clientOnlyEntries.addAll(getAdditionalClientOnlyEntries().get());
|
||||||
|
Collections.sort(clientOnlyEntries);
|
||||||
applyClientOnlyManifestAttributes(params, clientOnlyEntries);
|
applyClientOnlyManifestAttributes(params, clientOnlyEntries);
|
||||||
params.getClientOnlyEntries().set(clientOnlyEntries.stream().filter(s -> s.endsWith(".class")).toList());
|
params.getClientOnlyEntries().set(clientOnlyEntries.stream().filter(s -> s.endsWith(".class")).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getJarType().isPresent()) {
|
||||||
|
params.getManifestAttributes().put(MANIFEST_JAR_TYPE_KEY, getJarType().get());
|
||||||
|
}
|
||||||
|
|
||||||
action.execute(params);
|
action.execute(params);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -161,6 +176,7 @@ public abstract class AbstractRemapJarTask extends Jar {
|
|||||||
|
|
||||||
Property<Boolean> getArchivePreserveFileTimestamps();
|
Property<Boolean> getArchivePreserveFileTimestamps();
|
||||||
Property<Boolean> getArchiveReproducibleFileOrder();
|
Property<Boolean> getArchiveReproducibleFileOrder();
|
||||||
|
Property<ZipEntryCompression> getEntryCompression();
|
||||||
|
|
||||||
Property<JarManifestService> getJarManifestService();
|
Property<JarManifestService> getJarManifestService();
|
||||||
MapProperty<String, String> getManifestAttributes();
|
MapProperty<String, String> getManifestAttributes();
|
||||||
@@ -203,9 +219,10 @@ public abstract class AbstractRemapJarTask extends Jar {
|
|||||||
protected void rewriteJar() throws IOException {
|
protected void rewriteJar() throws IOException {
|
||||||
final boolean isReproducibleFileOrder = getParameters().getArchiveReproducibleFileOrder().get();
|
final boolean isReproducibleFileOrder = getParameters().getArchiveReproducibleFileOrder().get();
|
||||||
final boolean isPreserveFileTimestamps = getParameters().getArchivePreserveFileTimestamps().get();
|
final boolean isPreserveFileTimestamps = getParameters().getArchivePreserveFileTimestamps().get();
|
||||||
|
final ZipEntryCompression compression = getParameters().getEntryCompression().get();
|
||||||
|
|
||||||
if (isReproducibleFileOrder || !isPreserveFileTimestamps) {
|
if (isReproducibleFileOrder || !isPreserveFileTimestamps || compression != ZipEntryCompression.DEFLATED) {
|
||||||
ZipReprocessorUtil.reprocessZip(outputFile.toFile(), isReproducibleFileOrder, isPreserveFileTimestamps);
|
ZipReprocessorUtil.reprocessZip(outputFile.toFile(), isReproducibleFileOrder, isPreserveFileTimestamps, compression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,6 +168,8 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
|||||||
// Make outputs reproducible by default
|
// Make outputs reproducible by default
|
||||||
setReproducibleFileOrder(true);
|
setReproducibleFileOrder(true);
|
||||||
setPreserveFileTimestamps(false);
|
setPreserveFileTimestamps(false);
|
||||||
|
|
||||||
|
getJarType().set("classes");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupPreparationTask() {
|
private void setupPreparationTask() {
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ public abstract class RemapSourcesJarTask extends AbstractRemapJarTask {
|
|||||||
serviceManagerProvider = BuildSharedServiceManager.createForTask(this, getBuildEventsListenerRegistry());
|
serviceManagerProvider = BuildSharedServiceManager.createForTask(this, getBuildEventsListenerRegistry());
|
||||||
|
|
||||||
getClasspath().from(getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME));
|
getClasspath().from(getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME));
|
||||||
|
getJarType().set("sources");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import net.fabricmc.loom.LoomGradleExtension;
|
|||||||
import net.fabricmc.loom.LoomGradlePlugin;
|
import net.fabricmc.loom.LoomGradlePlugin;
|
||||||
import net.fabricmc.loom.configuration.InstallerData;
|
import net.fabricmc.loom.configuration.InstallerData;
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
|
import net.fabricmc.loom.util.LoomVersions;
|
||||||
|
|
||||||
public abstract class JarManifestService implements BuildService<JarManifestService.Params> {
|
public abstract class JarManifestService implements BuildService<JarManifestService.Params> {
|
||||||
interface Params extends BuildServiceParameters {
|
interface Params extends BuildServiceParameters {
|
||||||
@@ -63,7 +64,7 @@ public abstract class JarManifestService implements BuildService<JarManifestServ
|
|||||||
|
|
||||||
params.getGradleVersion().set(GradleVersion.current().getVersion());
|
params.getGradleVersion().set(GradleVersion.current().getVersion());
|
||||||
params.getLoomVersion().set(LoomGradlePlugin.LOOM_VERSION);
|
params.getLoomVersion().set(LoomGradlePlugin.LOOM_VERSION);
|
||||||
params.getMCEVersion().set(Constants.Dependencies.Versions.MIXIN_COMPILE_EXTENSIONS);
|
params.getMCEVersion().set(LoomVersions.MIXIN_COMPILE_EXTENSIONS.version());
|
||||||
params.getMinecraftVersion().set(project.provider(() -> extension.getMinecraftProvider().minecraftVersion()));
|
params.getMinecraftVersion().set(project.provider(() -> extension.getMinecraftProvider().minecraftVersion()));
|
||||||
params.getTinyRemapperVersion().set(tinyRemapperVersion.orElse("unknown"));
|
params.getTinyRemapperVersion().set(tinyRemapperVersion.orElse("unknown"));
|
||||||
params.getFabricLoaderVersion().set(project.provider(() -> Optional.ofNullable(extension.getInstallerData()).map(InstallerData::version).orElse("unknown")));
|
params.getFabricLoaderVersion().set(project.provider(() -> Optional.ofNullable(extension.getInstallerData()).map(InstallerData::version).orElse("unknown")));
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
|
|
||||||
import dev.architectury.tinyremapper.IMappingProvider;
|
import dev.architectury.tinyremapper.IMappingProvider;
|
||||||
@@ -78,6 +79,8 @@ public class TinyRemapperService implements SharedService {
|
|||||||
joiner.add(project.getPath());
|
joiner.add(project.getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension.getKnownIndyBsms().get().stream().sorted().forEach(joiner::add);
|
||||||
|
|
||||||
if (extension.isForge()) {
|
if (extension.isForge()) {
|
||||||
joiner.add("forge");
|
joiner.add("forge");
|
||||||
}
|
}
|
||||||
@@ -92,7 +95,7 @@ public class TinyRemapperService implements SharedService {
|
|||||||
mappings.add(gradleMixinMappingProvider(serviceManager, project.getGradle(), extension.getMappingConfiguration().mappingsIdentifier, from, to));
|
mappings.add(gradleMixinMappingProvider(serviceManager, project.getGradle(), extension.getMappingConfiguration().mappingsIdentifier, from, to));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TinyRemapperService(mappings, !legacyMixin, kotlinClasspathService);
|
return new TinyRemapperService(mappings, !legacyMixin, kotlinClasspathService, extension.getKnownIndyBsms().get());
|
||||||
});
|
});
|
||||||
|
|
||||||
service.readClasspath(remapJarTask.getClasspath().getFiles().stream().map(File::toPath).filter(Files::exists).toList());
|
service.readClasspath(remapJarTask.getClasspath().getFiles().stream().map(File::toPath).filter(Files::exists).toList());
|
||||||
@@ -132,8 +135,8 @@ public class TinyRemapperService implements SharedService {
|
|||||||
// Set to true once remapping has started, once set no inputs can be read.
|
// Set to true once remapping has started, once set no inputs can be read.
|
||||||
private boolean isRemapping = false;
|
private boolean isRemapping = false;
|
||||||
|
|
||||||
public TinyRemapperService(List<IMappingProvider> mappings, boolean useMixinExtension, @Nullable KotlinClasspath kotlinClasspath) {
|
public TinyRemapperService(List<IMappingProvider> mappings, boolean useMixinExtension, @Nullable KotlinClasspath kotlinClasspath, Set<String> knownIndyBsms) {
|
||||||
TinyRemapper.Builder builder = TinyRemapper.newRemapper();
|
TinyRemapper.Builder builder = TinyRemapper.newRemapper().withKnownIndyBsm(knownIndyBsms);
|
||||||
|
|
||||||
for (IMappingProvider provider : mappings) {
|
for (IMappingProvider provider : mappings) {
|
||||||
builder.withMappings(provider);
|
builder.withMappings(provider);
|
||||||
|
|||||||
@@ -108,46 +108,6 @@ public class Constants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Constants related to dependencies.
|
|
||||||
*/
|
|
||||||
public static final class Dependencies {
|
|
||||||
public static final String MIXIN_COMPILE_EXTENSIONS = "net.fabricmc:fabric-mixin-compile-extensions:";
|
|
||||||
public static final String DEV_LAUNCH_INJECTOR = "net.fabricmc:dev-launch-injector:";
|
|
||||||
public static final String TERMINAL_CONSOLE_APPENDER = "net.minecrell:terminalconsoleappender:";
|
|
||||||
public static final String JETBRAINS_ANNOTATIONS = "org.jetbrains:annotations:";
|
|
||||||
public static final String NATIVE_SUPPORT = "net.fabricmc:fabric-loom-native-support:";
|
|
||||||
public static final String JAVAX_ANNOTATIONS = "com.google.code.findbugs:jsr305:"; // I hate that I have to add these.
|
|
||||||
public static final String FORGE_RUNTIME = "dev.architectury:architectury-loom-runtime:";
|
|
||||||
public static final String ACCESS_TRANSFORMERS = "net.minecraftforge:accesstransformers:";
|
|
||||||
public static final String UNPROTECT = "io.github.juuxel:unprotect:";
|
|
||||||
// Used to upgrade the ASM version for the AT tool.
|
|
||||||
public static final String ASM = "org.ow2.asm:asm:";
|
|
||||||
|
|
||||||
private Dependencies() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constants for versions of dependencies.
|
|
||||||
*/
|
|
||||||
public static final class Versions {
|
|
||||||
public static final String MIXIN_COMPILE_EXTENSIONS = "0.6.0";
|
|
||||||
public static final String DEV_LAUNCH_INJECTOR = "0.2.1+build.8";
|
|
||||||
public static final String TERMINAL_CONSOLE_APPENDER = "1.2.0";
|
|
||||||
public static final String JETBRAINS_ANNOTATIONS = "24.0.1";
|
|
||||||
public static final String NATIVE_SUPPORT_VERSION = "1.0.1";
|
|
||||||
public static final String JAVAX_ANNOTATIONS = "3.0.2";
|
|
||||||
public static final String FORGE_RUNTIME = "1.1.8";
|
|
||||||
public static final String ACCESS_TRANSFORMERS = "3.0.1";
|
|
||||||
public static final String ACCESS_TRANSFORMERS_NEW = "8.0.5";
|
|
||||||
public static final String UNPROTECT = "1.2.0";
|
|
||||||
public static final String ASM = "9.3";
|
|
||||||
|
|
||||||
private Versions() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class MixinArguments {
|
public static final class MixinArguments {
|
||||||
public static final String IN_MAP_FILE_NAMED_INTERMEDIARY = "inMapFileNamedIntermediary";
|
public static final String IN_MAP_FILE_NAMED_INTERMEDIARY = "inMapFileNamedIntermediary";
|
||||||
public static final String OUT_MAP_FILE_NAMED_INTERMEDIARY = "outMapFileNamedIntermediary";
|
public static final String OUT_MAP_FILE_NAMED_INTERMEDIARY = "outMapFileNamedIntermediary";
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ public class SourceRemapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Set<File> files = project.getConfigurations()
|
Set<File> files = project.getConfigurations()
|
||||||
.detachedConfiguration(project.getDependencies().create(Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS))
|
.detachedConfiguration(project.getDependencies().create(LoomVersions.JETBRAINS_ANNOTATIONS.mavenNotation()))
|
||||||
.resolve();
|
.resolve();
|
||||||
|
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ public final class TinyRemapperHelper {
|
|||||||
.rebuildSourceFilenames(true)
|
.rebuildSourceFilenames(true)
|
||||||
.invalidLvNamePattern(MC_LV_PATTERN)
|
.invalidLvNamePattern(MC_LV_PATTERN)
|
||||||
.inferNameFromSameLvIndex(true)
|
.inferNameFromSameLvIndex(true)
|
||||||
|
.withKnownIndyBsm(extension.getKnownIndyBsms().get())
|
||||||
.extraPreApplyVisitor((cls, next) -> {
|
.extraPreApplyVisitor((cls, next) -> {
|
||||||
if (fixRecords && !cls.isRecord() && "java/lang/Record".equals(cls.getSuperName())) {
|
if (fixRecords && !cls.isRecord() && "java/lang/Record".equals(cls.getSuperName())) {
|
||||||
return new RecordComponentFixVisitor(next, mappingTree, intermediaryNsId);
|
return new RecordComponentFixVisitor(next, mappingTree, intermediaryNsId);
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.attribute.FileTime;
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
@@ -38,12 +37,10 @@ import java.util.zip.ZipEntry;
|
|||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
public class ZipReprocessorUtil {
|
import org.gradle.api.tasks.bundling.ZipEntryCompression;
|
||||||
/**
|
import org.intellij.lang.annotations.MagicConstant;
|
||||||
* See {@link org.gradle.api.internal.file.archive.ZipCopyAction} about this.
|
|
||||||
*/
|
|
||||||
private static final long CONSTANT_TIME_FOR_ZIP_ENTRIES = new GregorianCalendar(1980, Calendar.FEBRUARY, 1, 0, 0, 0).getTimeInMillis();
|
|
||||||
|
|
||||||
|
public class ZipReprocessorUtil {
|
||||||
private ZipReprocessorUtil() { }
|
private ZipReprocessorUtil() { }
|
||||||
|
|
||||||
private static final String MANIFEST_LOCATION = "META-INF/MANIFEST.MF";
|
private static final String MANIFEST_LOCATION = "META-INF/MANIFEST.MF";
|
||||||
@@ -92,6 +89,10 @@ public class ZipReprocessorUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void reprocessZip(File file, boolean reproducibleFileOrder, boolean preserveFileTimestamps) throws IOException {
|
public static void reprocessZip(File file, boolean reproducibleFileOrder, boolean preserveFileTimestamps) throws IOException {
|
||||||
|
reprocessZip(file, reproducibleFileOrder, preserveFileTimestamps, ZipEntryCompression.DEFLATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void reprocessZip(File file, boolean reproducibleFileOrder, boolean preserveFileTimestamps, ZipEntryCompression zipEntryCompression) throws IOException {
|
||||||
if (!reproducibleFileOrder && preserveFileTimestamps) {
|
if (!reproducibleFileOrder && preserveFileTimestamps) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -111,6 +112,8 @@ public class ZipReprocessorUtil {
|
|||||||
final var outZip = new ByteArrayOutputStream(entries.length);
|
final var outZip = new ByteArrayOutputStream(entries.length);
|
||||||
|
|
||||||
try (var zipOutputStream = new ZipOutputStream(outZip)) {
|
try (var zipOutputStream = new ZipOutputStream(outZip)) {
|
||||||
|
zipOutputStream.setMethod(zipOutputStreamCompressionMethod(zipEntryCompression));
|
||||||
|
|
||||||
for (ZipEntry entry : entries) {
|
for (ZipEntry entry : entries) {
|
||||||
ZipEntry newEntry = entry;
|
ZipEntry newEntry = entry;
|
||||||
|
|
||||||
@@ -119,6 +122,7 @@ public class ZipReprocessorUtil {
|
|||||||
setConstantFileTime(newEntry);
|
setConstantFileTime(newEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newEntry.setMethod(zipEntryCompressionMethod(zipEntryCompression));
|
||||||
copyZipEntry(zipOutputStream, newEntry, zipFile.getInputStream(entry));
|
copyZipEntry(zipOutputStream, newEntry, zipFile.getInputStream(entry));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,8 +177,23 @@ public class ZipReprocessorUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void setConstantFileTime(ZipEntry entry) {
|
private static void setConstantFileTime(ZipEntry entry) {
|
||||||
entry.setTime(ZipReprocessorUtil.CONSTANT_TIME_FOR_ZIP_ENTRIES);
|
// See https://github.com/openjdk/jdk/blob/master/test/jdk/java/util/zip/ZipFile/ZipEntryTimeBounds.java
|
||||||
entry.setLastModifiedTime(FileTime.fromMillis(ZipReprocessorUtil.CONSTANT_TIME_FOR_ZIP_ENTRIES));
|
entry.setTime(new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 0).getTimeInMillis());
|
||||||
entry.setLastAccessTime(FileTime.fromMillis(ZipReprocessorUtil.CONSTANT_TIME_FOR_ZIP_ENTRIES));
|
}
|
||||||
|
|
||||||
|
@MagicConstant(valuesFromClass = ZipOutputStream.class)
|
||||||
|
private static int zipOutputStreamCompressionMethod(ZipEntryCompression compression) {
|
||||||
|
return switch (compression) {
|
||||||
|
case STORED -> ZipOutputStream.STORED;
|
||||||
|
case DEFLATED -> ZipOutputStream.DEFLATED;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@MagicConstant(valuesFromClass = ZipEntry.class)
|
||||||
|
private static int zipEntryCompressionMethod(ZipEntryCompression compression) {
|
||||||
|
return switch (compression) {
|
||||||
|
case STORED -> ZipEntry.STORED;
|
||||||
|
case DEFLATED -> ZipEntry.DEFLATED;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,9 +62,11 @@ import net.fabricmc.loom.util.Checksum;
|
|||||||
public final class Download {
|
public final class Download {
|
||||||
private static final String E_TAG = "ETag";
|
private static final String E_TAG = "ETag";
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(Download.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(Download.class);
|
||||||
|
private static final Duration TIMEOUT = Duration.ofMinutes(1);
|
||||||
private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder()
|
private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder()
|
||||||
.followRedirects(HttpClient.Redirect.ALWAYS)
|
.followRedirects(HttpClient.Redirect.ALWAYS)
|
||||||
.proxy(ProxySelector.getDefault())
|
.proxy(ProxySelector.getDefault())
|
||||||
|
.connectTimeout(TIMEOUT)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static DownloadBuilder create(String url) throws URISyntaxException {
|
public static DownloadBuilder create(String url) throws URISyntaxException {
|
||||||
@@ -93,17 +95,20 @@ public final class Download {
|
|||||||
this.downloadAttempt = downloadAttempt;
|
this.downloadAttempt = downloadAttempt;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpRequest getRequest() {
|
private HttpRequest.Builder requestBuilder() {
|
||||||
return HttpRequest.newBuilder(url)
|
return HttpRequest.newBuilder(url)
|
||||||
|
.timeout(TIMEOUT)
|
||||||
.version(httpVersion)
|
.version(httpVersion)
|
||||||
.GET()
|
.GET();
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpRequest getRequest() {
|
||||||
|
return requestBuilder()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpRequest getETagRequest(String etag) {
|
private HttpRequest getETagRequest(String etag) {
|
||||||
return HttpRequest.newBuilder(url)
|
return requestBuilder()
|
||||||
.version(httpVersion)
|
|
||||||
.GET()
|
|
||||||
.header("If-None-Match", etag)
|
.header("If-None-Match", etag)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
@@ -129,7 +134,7 @@ public final class Download {
|
|||||||
|
|
||||||
if (!successful) {
|
if (!successful) {
|
||||||
progressListener.onEnd();
|
progressListener.onEnd();
|
||||||
throw error("HTTP request to (%s) returned unsuccessful status (%d)", url, statusCode);
|
throw statusError("HTTP request to (%s) returned unsuccessful status".formatted(url) + "(%d)", statusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
try (InputStream inputStream = decodeOutput(response)) {
|
try (InputStream inputStream = decodeOutput(response)) {
|
||||||
@@ -190,47 +195,12 @@ public final class Download {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success) {
|
if (!success) {
|
||||||
try {
|
throw statusError("HTTP request returned unsuccessful status (%d)", statusCode);
|
||||||
Files.deleteIfExists(output);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw error(e, "Failed to delete existing file");
|
|
||||||
}
|
|
||||||
|
|
||||||
final long length = Long.parseLong(response.headers().firstValue("Content-Length").orElse("-1"));
|
|
||||||
AtomicLong totalBytes = new AtomicLong(0);
|
|
||||||
|
|
||||||
try (OutputStream outputStream = Files.newOutputStream(output, StandardOpenOption.CREATE_NEW)) {
|
|
||||||
copyWithCallback(decodeOutput(response), outputStream, value -> {
|
|
||||||
if (length < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
progressListener.onProgress(totalBytes.addAndGet(value), length);
|
|
||||||
});
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw error(e, "Failed to decode and write download output");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Files.notExists(output)) {
|
|
||||||
throw error("No file was downloaded");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length > 0) {
|
|
||||||
try {
|
|
||||||
final long actualLength = Files.size(output);
|
|
||||||
|
|
||||||
if (actualLength != length) {
|
|
||||||
throw error("Unexpected file length of %d bytes, expected %d bytes".formatted(actualLength, length));
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw error("HTTP request returned unsuccessful status (%d)", statusCode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
downloadToPath(output, response);
|
||||||
|
|
||||||
if (useEtag) {
|
if (useEtag) {
|
||||||
final HttpHeaders headers = response.headers();
|
final HttpHeaders headers = response.headers();
|
||||||
final String responseETag = headers.firstValue(E_TAG.toLowerCase(Locale.ROOT)).orElse(null);
|
final String responseETag = headers.firstValue(E_TAG.toLowerCase(Locale.ROOT)).orElse(null);
|
||||||
@@ -260,6 +230,58 @@ public final class Download {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void downloadToPath(Path output, HttpResponse<InputStream> response) throws DownloadException {
|
||||||
|
// Download the file initially to a .part file
|
||||||
|
final Path partFile = getPartFile(output);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(output);
|
||||||
|
Files.deleteIfExists(partFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw error(e, "Failed to delete existing file");
|
||||||
|
}
|
||||||
|
|
||||||
|
final long length = Long.parseLong(response.headers().firstValue("Content-Length").orElse("-1"));
|
||||||
|
AtomicLong totalBytes = new AtomicLong(0);
|
||||||
|
|
||||||
|
try (OutputStream outputStream = Files.newOutputStream(partFile, StandardOpenOption.CREATE_NEW)) {
|
||||||
|
copyWithCallback(decodeOutput(response), outputStream, value -> {
|
||||||
|
if (length < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
progressListener.onProgress(totalBytes.addAndGet(value), length);
|
||||||
|
});
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw error(e, "Failed to decode and write download output");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Files.notExists(partFile)) {
|
||||||
|
throw error("No file was downloaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > 0) {
|
||||||
|
try {
|
||||||
|
final long actualLength = Files.size(partFile);
|
||||||
|
|
||||||
|
if (actualLength != length) {
|
||||||
|
throw error("Unexpected file length of %d bytes, expected %d bytes".formatted(actualLength, length));
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Once the file has been fully read, create a hard link to the destination file.
|
||||||
|
// And then remove the temporary file, this ensures that the output file only exists in fully populated state.
|
||||||
|
Files.createLink(output, partFile);
|
||||||
|
Files.delete(partFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw error(e, "Failed to complete download");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void copyWithCallback(InputStream is, OutputStream os, IntConsumer consumer) throws IOException {
|
private void copyWithCallback(InputStream is, OutputStream os, IntConsumer consumer) throws IOException {
|
||||||
byte[] buffer = new byte[1024];
|
byte[] buffer = new byte[1024];
|
||||||
int length;
|
int length;
|
||||||
@@ -389,6 +411,18 @@ public final class Download {
|
|||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(getLockFile(output));
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(getPartFile(output));
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A faster exists check
|
// A faster exists check
|
||||||
@@ -405,6 +439,10 @@ public final class Download {
|
|||||||
return output.resolveSibling(output.getFileName() + ".lock");
|
return output.resolveSibling(output.getFileName() + ".lock");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Path getPartFile(Path output) {
|
||||||
|
return output.resolveSibling(output.getFileName() + ".part");
|
||||||
|
}
|
||||||
|
|
||||||
private boolean getAndResetLock(Path output) throws DownloadException {
|
private boolean getAndResetLock(Path output) throws DownloadException {
|
||||||
final Path lock = getLockFile(output);
|
final Path lock = getLockFile(output);
|
||||||
final boolean exists = exists(lock);
|
final boolean exists = exists(lock);
|
||||||
@@ -430,6 +468,10 @@ public final class Download {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DownloadException statusError(String message, int statusCode) {
|
||||||
|
return new DownloadException(String.format(Locale.ENGLISH, message, statusCode), statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
private DownloadException error(String message, Object... args) {
|
private DownloadException error(String message, Object... args) {
|
||||||
return new DownloadException(String.format(Locale.ENGLISH, message, args));
|
return new DownloadException(String.format(Locale.ENGLISH, message, args));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,6 +158,11 @@ public class DownloadBuilder {
|
|||||||
|
|
||||||
return supplier.get(build(i));
|
return supplier.get(build(i));
|
||||||
} catch (DownloadException e) {
|
} catch (DownloadException e) {
|
||||||
|
if (e.getStatusCode() == 404) {
|
||||||
|
// Don't retry on 404's
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
if (i == maxRetries) {
|
if (i == maxRetries) {
|
||||||
throw new DownloadException(String.format(Locale.ENGLISH, "Failed download after %d attempts", maxRetries), e);
|
throw new DownloadException(String.format(Locale.ENGLISH, "Failed download after %d attempts", maxRetries), e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,15 +27,32 @@ package net.fabricmc.loom.util.download;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class DownloadException extends IOException {
|
public class DownloadException extends IOException {
|
||||||
|
private final int statusCode;
|
||||||
|
|
||||||
public DownloadException(String message) {
|
public DownloadException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
|
statusCode = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DownloadException(String message, int statusCode) {
|
||||||
|
super(message);
|
||||||
|
this.statusCode = statusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownloadException(String message, Throwable cause) {
|
public DownloadException(String message, Throwable cause) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
|
statusCode = cause instanceof DownloadException downloadException ? downloadException.getStatusCode() : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownloadException(Throwable cause) {
|
public DownloadException(Throwable cause) {
|
||||||
super(cause);
|
super(cause);
|
||||||
|
statusCode = cause instanceof DownloadException downloadException ? downloadException.getStatusCode() : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return -1 when the status code is unknown.
|
||||||
|
*/
|
||||||
|
public int getStatusCode() {
|
||||||
|
return statusCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,18 +58,18 @@ class KotlinClassMetadataRemappingAnnotationVisitor(private val remapper: Remapp
|
|||||||
|
|
||||||
when (val metadata = KotlinClassMetadata.read(header)) {
|
when (val metadata = KotlinClassMetadata.read(header)) {
|
||||||
is KotlinClassMetadata.Class -> {
|
is KotlinClassMetadata.Class -> {
|
||||||
var klass = metadata.toKmClass()
|
var klass = metadata.kmClass
|
||||||
klass = KotlinClassRemapper(remapper).remap(klass)
|
klass = KotlinClassRemapper(remapper).remap(klass)
|
||||||
val remapped = KotlinClassMetadata.writeClass(klass, header.metadataVersion, header.extraInt).annotationData
|
val remapped = KotlinClassMetadata.writeClass(klass, header.metadataVersion, header.extraInt)
|
||||||
writeClassHeader(remapped)
|
writeClassHeader(remapped)
|
||||||
validateKotlinClassHeader(remapped, header)
|
validateKotlinClassHeader(remapped, header)
|
||||||
}
|
}
|
||||||
is KotlinClassMetadata.SyntheticClass -> {
|
is KotlinClassMetadata.SyntheticClass -> {
|
||||||
var klambda = metadata.toKmLambda()
|
var klambda = metadata.kmLambda
|
||||||
|
|
||||||
if (klambda != null) {
|
if (klambda != null) {
|
||||||
klambda = KotlinClassRemapper(remapper).remap(klambda)
|
klambda = KotlinClassRemapper(remapper).remap(klambda)
|
||||||
val remapped = KotlinClassMetadata.writeLambda(klambda, header.metadataVersion, header.extraInt).annotationData
|
val remapped = KotlinClassMetadata.writeLambda(klambda, header.metadataVersion, header.extraInt)
|
||||||
writeClassHeader(remapped)
|
writeClassHeader(remapped)
|
||||||
validateKotlinClassHeader(remapped, header)
|
validateKotlinClassHeader(remapped, header)
|
||||||
} else {
|
} else {
|
||||||
@@ -77,20 +77,21 @@ class KotlinClassMetadataRemappingAnnotationVisitor(private val remapper: Remapp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is KotlinClassMetadata.FileFacade -> {
|
is KotlinClassMetadata.FileFacade -> {
|
||||||
var kpackage = metadata.toKmPackage()
|
var kpackage = metadata.kmPackage
|
||||||
kpackage = KotlinClassRemapper(remapper).remap(kpackage)
|
kpackage = KotlinClassRemapper(remapper).remap(kpackage)
|
||||||
val remapped = KotlinClassMetadata.writeFileFacade(kpackage, header.metadataVersion, header.extraInt).annotationData
|
val remapped = KotlinClassMetadata.writeFileFacade(kpackage, header.metadataVersion, header.extraInt)
|
||||||
writeClassHeader(remapped)
|
writeClassHeader(remapped)
|
||||||
validateKotlinClassHeader(remapped, header)
|
validateKotlinClassHeader(remapped, header)
|
||||||
}
|
}
|
||||||
is KotlinClassMetadata.MultiFileClassPart -> {
|
is KotlinClassMetadata.MultiFileClassPart -> {
|
||||||
var kpackage = metadata.toKmPackage()
|
var kpackage = metadata.kmPackage
|
||||||
kpackage = KotlinClassRemapper(remapper).remap(kpackage)
|
kpackage = KotlinClassRemapper(remapper).remap(kpackage)
|
||||||
val remapped = KotlinClassMetadata.writeMultiFileClassPart(kpackage, metadata.facadeClassName, metadata.annotationData.metadataVersion, metadata.annotationData.extraInt).annotationData
|
val wrapper = KotlinClassMetadataWrapper(metadata)
|
||||||
|
val remapped = KotlinClassMetadata.writeMultiFileClassPart(kpackage, metadata.facadeClassName, wrapper.annotationData.metadataVersion, wrapper.annotationData.extraInt)
|
||||||
writeClassHeader(remapped)
|
writeClassHeader(remapped)
|
||||||
validateKotlinClassHeader(remapped, header)
|
validateKotlinClassHeader(remapped, header)
|
||||||
}
|
}
|
||||||
is KotlinClassMetadata.MultiFileClassFacade, is KotlinClassMetadata.Unknown, null -> {
|
is KotlinClassMetadata.MultiFileClassFacade, is KotlinClassMetadata.Unknown -> {
|
||||||
// do nothing
|
// do nothing
|
||||||
accept(next)
|
accept(next)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,10 +49,10 @@ import kotlinx.metadata.internal.extensions.KmTypeAliasExtension
|
|||||||
import kotlinx.metadata.internal.extensions.KmTypeExtension
|
import kotlinx.metadata.internal.extensions.KmTypeExtension
|
||||||
import kotlinx.metadata.internal.extensions.KmTypeParameterExtension
|
import kotlinx.metadata.internal.extensions.KmTypeParameterExtension
|
||||||
import kotlinx.metadata.internal.extensions.KmValueParameterExtension
|
import kotlinx.metadata.internal.extensions.KmValueParameterExtension
|
||||||
import kotlinx.metadata.isLocal
|
import kotlinx.metadata.isLocalClassName
|
||||||
import kotlinx.metadata.jvm.JvmFieldSignature
|
import kotlinx.metadata.jvm.JvmFieldSignature
|
||||||
import kotlinx.metadata.jvm.JvmMethodSignature
|
import kotlinx.metadata.jvm.JvmMethodSignature
|
||||||
import kotlinx.metadata.jvm.jvmInternalName
|
import kotlinx.metadata.jvm.toJvmInternalName
|
||||||
import org.objectweb.asm.commons.Remapper
|
import org.objectweb.asm.commons.Remapper
|
||||||
|
|
||||||
@OptIn(ExperimentalContextReceivers::class)
|
@OptIn(ExperimentalContextReceivers::class)
|
||||||
@@ -86,8 +86,8 @@ class KotlinClassRemapper(private val remapper: Remapper) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun remap(name: ClassName): ClassName {
|
private fun remap(name: ClassName): ClassName {
|
||||||
val local = name.isLocal
|
val local = name.isLocalClassName()
|
||||||
val remapped = remapper.map(name.jvmInternalName).replace('$', '.')
|
val remapped = remapper.map(name.toJvmInternalName()).replace('$', '.')
|
||||||
|
|
||||||
if (local) {
|
if (local) {
|
||||||
return ".$remapped"
|
return ".$remapped"
|
||||||
@@ -241,10 +241,10 @@ class KotlinClassRemapper(private val remapper: Remapper) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun remap(signature: JvmMethodSignature): JvmMethodSignature {
|
private fun remap(signature: JvmMethodSignature): JvmMethodSignature {
|
||||||
return JvmMethodSignature(signature.name, remapper.mapMethodDesc(signature.desc))
|
return JvmMethodSignature(signature.name, remapper.mapMethodDesc(signature.descriptor))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun remap(signature: JvmFieldSignature): JvmFieldSignature {
|
private fun remap(signature: JvmFieldSignature): JvmFieldSignature {
|
||||||
return JvmFieldSignature(signature.name, remapper.mapDesc(signature.desc))
|
return JvmFieldSignature(signature.name, remapper.mapDesc(signature.descriptor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
<!-- System out -->
|
<!-- System out -->
|
||||||
<Console name="SysOut" target="SYSTEM_OUT">
|
<Console name="SysOut" target="SYSTEM_OUT">
|
||||||
|
<!-- Filter out the authentication error when starting in development -->
|
||||||
|
<RegexFilter regex="^Failed to verify authentication$" onMatch="DENY" onMismatch="ACCEPT"/>
|
||||||
<PatternLayout>
|
<PatternLayout>
|
||||||
<LoggerNamePatternSelector defaultPattern="%style{[%d{HH:mm:ss}]}{blue} %highlight{[%t/%level]}{FATAL=red, ERROR=red, WARN=yellow, INFO=green, DEBUG=green, TRACE=blue} %style{(%logger{1})}{cyan} %highlight{%msg%n}{FATAL=red, ERROR=red, WARN=normal, INFO=normal, DEBUG=normal, TRACE=normal}" disableAnsi="${sys:fabric.log.disableAnsi:-true}">
|
<LoggerNamePatternSelector defaultPattern="%style{[%d{HH:mm:ss}]}{blue} %highlight{[%t/%level]}{FATAL=red, ERROR=red, WARN=yellow, INFO=green, DEBUG=green, TRACE=blue} %style{(%logger{1})}{cyan} %highlight{%msg%n}{FATAL=red, ERROR=red, WARN=normal, INFO=normal, DEBUG=normal, TRACE=normal}" disableAnsi="${sys:fabric.log.disableAnsi:-true}">
|
||||||
<!-- Dont show the logger name for minecraft classes-->
|
<!-- Dont show the logger name for minecraft classes-->
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ package net.fabricmc.loom.test
|
|||||||
import org.gradle.util.GradleVersion
|
import org.gradle.util.GradleVersion
|
||||||
|
|
||||||
class LoomTestConstants {
|
class LoomTestConstants {
|
||||||
private final static String NIGHTLY_VERSION = "8.3-20230702222859+0000"
|
private final static String NIGHTLY_VERSION = LoomTestVersions.GRADLE_NIGHTLY.version()
|
||||||
private final static boolean NIGHTLY_EXISTS = nightlyExists(NIGHTLY_VERSION)
|
private final static boolean NIGHTLY_EXISTS = nightlyExists(NIGHTLY_VERSION)
|
||||||
|
|
||||||
// Test against the version of Gradle being used to build loom
|
// Test against the version of Gradle being used to build loom
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ class DecompileTest extends Specification implements GradleProjectTestTrait {
|
|||||||
decompiler | task | version
|
decompiler | task | version
|
||||||
'fernflower' | "genSourcesWithFernFlower" | PRE_RELEASE_GRADLE
|
'fernflower' | "genSourcesWithFernFlower" | PRE_RELEASE_GRADLE
|
||||||
'cfr' | "genSourcesWithCfr" | PRE_RELEASE_GRADLE
|
'cfr' | "genSourcesWithCfr" | PRE_RELEASE_GRADLE
|
||||||
|
'vineflower' | "genSourcesWithVineflower" | PRE_RELEASE_GRADLE
|
||||||
}
|
}
|
||||||
|
|
||||||
@Unroll
|
@Unroll
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait {
|
|||||||
setup:
|
setup:
|
||||||
def gradle = gradleProject(
|
def gradle = gradleProject(
|
||||||
repo: "https://github.com/FabricMC/fabric.git",
|
repo: "https://github.com/FabricMC/fabric.git",
|
||||||
commit: "1ac061308b9d70fa6aad5db3dcc5580cb6ac71cb",
|
commit: "f091af96c53963fadf9dbc391c67bb40e5678a96",
|
||||||
version: version,
|
version: version,
|
||||||
patch: "fabric_api"
|
patch: "fabric_api"
|
||||||
)
|
)
|
||||||
@@ -57,7 +57,7 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait {
|
|||||||
.replace('id "fabric-loom" version "0.9.50"', 'id "dev.architectury.loom"')
|
.replace('id "fabric-loom" version "0.9.50"', 'id "dev.architectury.loom"')
|
||||||
.replace('"fabric-loom"', '"dev.architectury.loom"')
|
.replace('"fabric-loom"', '"dev.architectury.loom"')
|
||||||
|
|
||||||
def server = ServerRunner.create(gradle.projectDir, "1.20.1")
|
def server = ServerRunner.create(gradle.projectDir, "23w33a")
|
||||||
.withMod(gradle.getOutputFile("fabric-api-${API_VERSION}.jar"))
|
.withMod(gradle.getOutputFile("fabric-api-${API_VERSION}.jar"))
|
||||||
when:
|
when:
|
||||||
def result = gradle.run(tasks: [
|
def result = gradle.run(tasks: [
|
||||||
@@ -79,8 +79,8 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait {
|
|||||||
result.task(":build").outcome == SUCCESS
|
result.task(":build").outcome == SUCCESS
|
||||||
result.task(":prepareRemapJar").outcome == SUCCESS
|
result.task(":prepareRemapJar").outcome == SUCCESS
|
||||||
|
|
||||||
new File(gradle.mavenLocalDir, "net/fabricmc/fabric-api/fabric-biome-api-v1/13.0.10/fabric-biome-api-v1-13.0.10.jar").exists()
|
new File(gradle.mavenLocalDir, "net/fabricmc/fabric-api/fabric-biome-api-v1/13.0.11/fabric-biome-api-v1-13.0.11.jar").exists()
|
||||||
new File(gradle.mavenLocalDir, "net/fabricmc/fabric-api/fabric-biome-api-v1/13.0.10/fabric-biome-api-v1-13.0.10-sources.jar").exists()
|
new File(gradle.mavenLocalDir, "net/fabricmc/fabric-api/fabric-biome-api-v1/13.0.11/fabric-biome-api-v1-13.0.11-sources.jar").exists()
|
||||||
|
|
||||||
serverResult.successful()
|
serverResult.successful()
|
||||||
serverResult.output.contains("- fabric-api $API_VERSION")
|
serverResult.output.contains("- fabric-api $API_VERSION")
|
||||||
|
|||||||
@@ -55,13 +55,13 @@ class ReproducibleBuildTest extends Specification implements GradleProjectTestTr
|
|||||||
|
|
||||||
where:
|
where:
|
||||||
version | modHash | sourceHash
|
version | modHash | sourceHash
|
||||||
DEFAULT_GRADLE | "174c9b52f4bc6d489548d11b42e853cf" | [
|
DEFAULT_GRADLE | "97240b42385adfaa1952e9c4ea942f71" | [
|
||||||
"5e6e56df303b4fbaaef372d6f143dbfc",
|
"61438feb9bd548788bbc637637d202fc",
|
||||||
"92b6fbffd0bd14bf3c626750eb86c264"
|
"185ad8396d89b726064682bf22572036"
|
||||||
]
|
]
|
||||||
PRE_RELEASE_GRADLE | "174c9b52f4bc6d489548d11b42e853cf" | [
|
PRE_RELEASE_GRADLE | "97240b42385adfaa1952e9c4ea942f71" | [
|
||||||
"5e6e56df303b4fbaaef372d6f143dbfc",
|
"61438feb9bd548788bbc637637d202fc",
|
||||||
"92b6fbffd0bd14bf3c626750eb86c264"
|
"185ad8396d89b726064682bf22572036"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.test.unit
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import spock.lang.Specification
|
||||||
|
|
||||||
|
import net.fabricmc.loom.configuration.FabricApiExtension
|
||||||
|
import net.fabricmc.loom.test.util.GradleTestUtil
|
||||||
|
|
||||||
|
class FabricApiExtensionTest extends Specification {
|
||||||
|
def "get module version"() {
|
||||||
|
when:
|
||||||
|
def fabricApi = new FabricApiExtension() {
|
||||||
|
Project project = GradleTestUtil.mockProject()
|
||||||
|
}
|
||||||
|
def version = fabricApi.moduleVersion(moduleName, apiVersion)
|
||||||
|
|
||||||
|
then:
|
||||||
|
version == expectedVersion
|
||||||
|
|
||||||
|
where:
|
||||||
|
moduleName | apiVersion | expectedVersion
|
||||||
|
"fabric-api-base" | "0.88.3+1.20.2" | "0.4.32+fce67b3299" // Normal module, new version
|
||||||
|
"fabric-api-base" | "0.13.1+build.257-1.14" | "0.1.2+28f8190f42" // Normal module, old version before deprecated modules.
|
||||||
|
"fabric-networking-v0" | "0.88.0+1.20.1" | "0.3.50+df3654b377" // Deprecated module, opt-out version
|
||||||
|
"fabric-networking-v0" | "0.85.0+1.20.1" | "0.3.48+df3654b377" // Deprecated module, opt-in version
|
||||||
|
}
|
||||||
|
|
||||||
|
def "unknown module"() {
|
||||||
|
when:
|
||||||
|
def fabricApi = new FabricApiExtension() {
|
||||||
|
Project project = GradleTestUtil.mockProject()
|
||||||
|
}
|
||||||
|
fabricApi.moduleVersion("fabric-api-unknown", apiVersion)
|
||||||
|
|
||||||
|
then:
|
||||||
|
def e = thrown RuntimeException
|
||||||
|
e.getMessage() == "Failed to find module version for module: fabric-api-unknown"
|
||||||
|
|
||||||
|
where:
|
||||||
|
apiVersion | _
|
||||||
|
"0.88.0+1.20.1" | _ // Deprecated opt-out
|
||||||
|
"0.85.0+1.20.1" | _ // Deprecated opt-int
|
||||||
|
"0.13.1+build.257-1.14" | _ // No deprecated modules
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ package net.fabricmc.loom.test.unit
|
|||||||
|
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
|
import java.time.ZoneId
|
||||||
|
|
||||||
import spock.lang.Specification
|
import spock.lang.Specification
|
||||||
|
|
||||||
@@ -155,6 +156,9 @@ class ZipUtilsTest extends Specification {
|
|||||||
|
|
||||||
def "append zip entry"() {
|
def "append zip entry"() {
|
||||||
given:
|
given:
|
||||||
|
def currentTimezone = TimeZone.getDefault()
|
||||||
|
TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of(timezone)))
|
||||||
|
|
||||||
// Create a reproducible input zip
|
// Create a reproducible input zip
|
||||||
def dir = Files.createTempDirectory("loom-zip-test")
|
def dir = Files.createTempDirectory("loom-zip-test")
|
||||||
def zip = Files.createTempFile("loom-zip-test", ".zip")
|
def zip = Files.createTempFile("loom-zip-test", ".zip")
|
||||||
@@ -167,9 +171,21 @@ class ZipUtilsTest extends Specification {
|
|||||||
// Add an entry to it
|
// Add an entry to it
|
||||||
ZipReprocessorUtil.appendZipEntry(zip.toFile(), "fabric.mod.json", "Some text".getBytes(StandardCharsets.UTF_8))
|
ZipReprocessorUtil.appendZipEntry(zip.toFile(), "fabric.mod.json", "Some text".getBytes(StandardCharsets.UTF_8))
|
||||||
|
|
||||||
|
// Reset the timezone back
|
||||||
|
TimeZone.setDefault(currentTimezone)
|
||||||
|
|
||||||
then:
|
then:
|
||||||
ZipUtils.unpack(zip, "text.txt") == "hello world".bytes
|
ZipUtils.unpack(zip, "text.txt") == "hello world".bytes
|
||||||
ZipUtils.unpack(zip, "fabric.mod.json") == "Some text".bytes
|
ZipUtils.unpack(zip, "fabric.mod.json") == "Some text".bytes
|
||||||
Checksum.sha1Hex(zip) == "232ecda4c770bde8ba618e7a194a4f7b57928dc5"
|
Checksum.sha1Hex(zip) == "1b06cc0aaa65ab2b0d423fe33431ff5bd14bf9c8"
|
||||||
|
|
||||||
|
where:
|
||||||
|
timezone | _
|
||||||
|
"UTC" | _
|
||||||
|
"US/Central" | _
|
||||||
|
"Europe/London" | _
|
||||||
|
"Australia/Sydney" | _
|
||||||
|
"Etc/GMT-6" | _
|
||||||
|
"Etc/GMT+9" | _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,16 +76,33 @@ class DownloadFileTest extends DownloadTest {
|
|||||||
def "File: Not found"() {
|
def "File: Not found"() {
|
||||||
setup:
|
setup:
|
||||||
server.get("/fileNotfound") {
|
server.get("/fileNotfound") {
|
||||||
it.status(404)
|
it.status(HttpStatus.NOT_FOUND)
|
||||||
}
|
}
|
||||||
|
|
||||||
def output = new File(File.createTempDir(), "file.txt").toPath()
|
def output = new File(File.createTempDir(), "file.txt").toPath()
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def result = Download.create("$PATH/stringNotFound").downloadPath(output)
|
def result = Download.create("$PATH/fileNotfound").downloadPath(output)
|
||||||
|
|
||||||
then:
|
then:
|
||||||
thrown DownloadException
|
def e = thrown DownloadException
|
||||||
|
e.statusCode == 404
|
||||||
|
}
|
||||||
|
|
||||||
|
def "File: Server error"() {
|
||||||
|
setup:
|
||||||
|
server.get("/fileServerError") {
|
||||||
|
it.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
}
|
||||||
|
|
||||||
|
def output = new File(File.createTempDir(), "file.txt").toPath()
|
||||||
|
|
||||||
|
when:
|
||||||
|
def result = Download.create("$PATH/fileServerError").downloadPath(output)
|
||||||
|
|
||||||
|
then:
|
||||||
|
def e = thrown DownloadException
|
||||||
|
e.statusCode == 500
|
||||||
}
|
}
|
||||||
|
|
||||||
def "Cache: Sha1"() {
|
def "Cache: Sha1"() {
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class DownloadStringTest extends DownloadTest {
|
|||||||
def "String: Not found"() {
|
def "String: Not found"() {
|
||||||
setup:
|
setup:
|
||||||
server.get("/stringNotFound") {
|
server.get("/stringNotFound") {
|
||||||
it.status(404)
|
it.status(HttpStatus.NOT_FOUND)
|
||||||
}
|
}
|
||||||
|
|
||||||
when:
|
when:
|
||||||
@@ -55,7 +55,24 @@ class DownloadStringTest extends DownloadTest {
|
|||||||
.downloadString()
|
.downloadString()
|
||||||
|
|
||||||
then:
|
then:
|
||||||
thrown DownloadException
|
def e = thrown DownloadException
|
||||||
|
e.statusCode == 404
|
||||||
|
}
|
||||||
|
|
||||||
|
def "String: Server error"() {
|
||||||
|
setup:
|
||||||
|
server.get("/stringNotFound") {
|
||||||
|
it.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
}
|
||||||
|
|
||||||
|
when:
|
||||||
|
def result = Download.create("$PATH/stringNotFound")
|
||||||
|
.maxRetries(3) // Ensure we still error as expected when retrying
|
||||||
|
.downloadString()
|
||||||
|
|
||||||
|
then:
|
||||||
|
def e = thrown DownloadException
|
||||||
|
e.statusCode == 500
|
||||||
}
|
}
|
||||||
|
|
||||||
def "String: Redirect"() {
|
def "String: Redirect"() {
|
||||||
@@ -97,6 +114,25 @@ class DownloadStringTest extends DownloadTest {
|
|||||||
result == "Hello World 3"
|
result == "Hello World 3"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "String: Retries 404"() {
|
||||||
|
setup:
|
||||||
|
int requests = 0
|
||||||
|
server.get("/retryString") {
|
||||||
|
requests ++
|
||||||
|
it.status(HttpStatus.NOT_FOUND)
|
||||||
|
}
|
||||||
|
|
||||||
|
when:
|
||||||
|
def result = Download.create("$PATH/retryString")
|
||||||
|
.maxRetries(3)
|
||||||
|
.downloadString()
|
||||||
|
|
||||||
|
then:
|
||||||
|
def e = thrown DownloadException
|
||||||
|
e.statusCode == 404
|
||||||
|
requests == 1
|
||||||
|
}
|
||||||
|
|
||||||
def "String: File cache"() {
|
def "String: File cache"() {
|
||||||
setup:
|
setup:
|
||||||
server.get("/downloadString2") {
|
server.get("/downloadString2") {
|
||||||
|
|||||||
@@ -36,12 +36,16 @@ import org.gradle.api.provider.Property
|
|||||||
import org.gradle.api.tasks.SourceSet
|
import org.gradle.api.tasks.SourceSet
|
||||||
import org.gradle.api.tasks.util.PatternFilterable
|
import org.gradle.api.tasks.util.PatternFilterable
|
||||||
import org.jetbrains.annotations.Nullable
|
import org.jetbrains.annotations.Nullable
|
||||||
|
import org.mockito.invocation.InvocationOnMock
|
||||||
|
import org.mockito.stubbing.Answer
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension
|
import net.fabricmc.loom.LoomGradleExtension
|
||||||
|
import net.fabricmc.loom.extension.LoomFiles
|
||||||
|
import net.fabricmc.loom.test.LoomTestConstants
|
||||||
|
import net.fabricmc.loom.util.download.Download
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any
|
import static org.mockito.ArgumentMatchers.any
|
||||||
import static org.mockito.Mockito.mock
|
import static org.mockito.Mockito.*
|
||||||
import static org.mockito.Mockito.when
|
|
||||||
|
|
||||||
class GradleTestUtil {
|
class GradleTestUtil {
|
||||||
static <T> Property<T> mockProperty(T value) {
|
static <T> Property<T> mockProperty(T value) {
|
||||||
@@ -73,7 +77,18 @@ class GradleTestUtil {
|
|||||||
|
|
||||||
static LoomGradleExtension mockLoomGradleExtension() {
|
static LoomGradleExtension mockLoomGradleExtension() {
|
||||||
def mock = mock(LoomGradleExtension.class)
|
def mock = mock(LoomGradleExtension.class)
|
||||||
|
def loomFiles = mockLoomFiles()
|
||||||
when(mock.refreshDeps()).thenReturn(false)
|
when(mock.refreshDeps()).thenReturn(false)
|
||||||
|
when(mock.getFiles()).thenReturn(loomFiles)
|
||||||
|
when(mock.download(any())).thenAnswer {
|
||||||
|
Download.create(it.getArgument(0))
|
||||||
|
}
|
||||||
|
return mock
|
||||||
|
}
|
||||||
|
|
||||||
|
static LoomFiles mockLoomFiles() {
|
||||||
|
def mock = mock(LoomFiles.class, new RequiresStubAnswer())
|
||||||
|
doReturn(LoomTestConstants.TEST_DIR).when(mock).getUserCache()
|
||||||
return mock
|
return mock
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,4 +136,10 @@ class GradleTestUtil {
|
|||||||
def mock = mock(RepositoryHandler.class)
|
def mock = mock(RepositoryHandler.class)
|
||||||
return mock
|
return mock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class RequiresStubAnswer implements Answer<Object> {
|
||||||
|
Object answer(InvocationOnMock invocation) throws Throwable {
|
||||||
|
throw new RuntimeException("${invocation.getMethod().getName()} is not stubbed")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,12 @@ import java.util.concurrent.TimeUnit
|
|||||||
|
|
||||||
import groovy.transform.Immutable
|
import groovy.transform.Immutable
|
||||||
|
|
||||||
|
import net.fabricmc.loom.test.LoomTestVersions
|
||||||
import net.fabricmc.loom.util.download.Download
|
import net.fabricmc.loom.util.download.Download
|
||||||
|
|
||||||
class ServerRunner {
|
class ServerRunner {
|
||||||
static final String LOADER_VERSION = "0.14.21"
|
static final String LOADER_VERSION = LoomTestVersions.FABRIC_LOADER.version()
|
||||||
static final String INSTALLER_VERSION = "0.11.1"
|
static final String INSTALLER_VERSION = LoomTestVersions.FABRIC_INSTALLER.version()
|
||||||
static final Map<String, String> FABRIC_API_URLS = [
|
static final Map<String, String> FABRIC_API_URLS = [
|
||||||
"1.16.5": "https://github.com/FabricMC/fabric/releases/download/0.37.1%2B1.16/fabric-api-0.37.1+1.16.jar",
|
"1.16.5": "https://github.com/FabricMC/fabric/releases/download/0.37.1%2B1.16/fabric-api-0.37.1+1.16.jar",
|
||||||
"1.17.1": "https://github.com/FabricMC/fabric/releases/download/0.37.1%2B1.17/fabric-api-0.37.1+1.17.jar"
|
"1.17.1": "https://github.com/FabricMC/fabric/releases/download/0.37.1%2B1.17/fabric-api-0.37.1+1.17.jar"
|
||||||
|
|||||||
Reference in New Issue
Block a user