diff --git a/build.gradle b/build.gradle index 34c8864..1fa4b5a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,28 +1,23 @@ -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath libs.bundles.asm - } -} - plugins { id 'java' id 'idea' id 'eclipse' id 'maven-publish' - id 'net.minecraftforge.licenser' version '1.1.0' - id 'net.minecraftforge.gradleutils' version '[2.3,2.4)' - id 'com.github.ben-manes.versions' version '0.52.0' + alias libs.plugins.licenser + alias libs.plugins.gradleutils + alias libs.plugins.versions } +final projectDisplayName = 'Srg2Source' +final projectVendor = 'Forge Development LLC' +final projectArtifactId = base.archivesName = 'srg2source' +description = 'Srg2Source library for ForgeGradle' group = 'net.minecraftforge' -archivesBaseName = 'srg2source' -version = gradleutils.tagOffsetVersion +version = gitversion.tagOffset java { toolchain.languageVersion = JavaLanguageVersion.of(17) + withSourcesJar() } @@ -31,12 +26,6 @@ configurations { implementation.extendsFrom shadow } -repositories { - //mavenLocal() - maven gradleutils.forgeMaven - mavenCentral() -} - dependencies { implementation(libs.securemodules) implementation(libs.nulls) @@ -55,149 +44,61 @@ changelog { from '8.0' } -tasks.named('jar', Jar).configure { +license { + header = rootProject.file('LICENSE-header.txt') + include 'net/minecraftforge/' +} + +tasks.register('patchJDT', PatchJDTClasses) { + targets.add(PatchJDTClasses.COMPILATION_UNIT_RESOLVER) + targets.add(PatchJDTClasses.RANGE_EXTRACTOR) + libraries.from(unpatchedJar.archiveFile) + libraries.from(configurations.shadow.filter { !it.isDirectory() }) + output = project.layout.buildDirectory.file("patch_jdt.jar") +} + +tasks.named('jar', Jar) { exclude 'data/**' manifest { attributes([ 'Automatic-Module-Name': 'net.minecraftforge.srg2source', - 'Main-Class': 'net.minecraftforge.srg2source.ConsoleTool' + 'Main-Class' : 'net.minecraftforge.srg2source.ConsoleTool' ] as LinkedHashMap) attributes([ - 'Specification-Title': 'Srg2Source', - 'Specification-Vendor': 'Forge Development LLC', - 'Specification-Version': gradleutils.gitInfo.tag, - 'Implementation-Title': 'Srg2Source', - 'Implementation-Vendor': 'Forge Development LLC', + 'Specification-Title' : projectDisplayName, + 'Specification-Vendor' : projectVendor, + 'Specification-Version' : gitversion.info.tag, + 'Implementation-Title' : projectDisplayName, + 'Implementation-Vendor' : projectVendor, 'Implementation-Version': project.version ] as LinkedHashMap, 'net/minecraftforge/srg2source/') } } -tasks.register('shadowJarPatched', Jar).configure { +tasks.register('shadowJarPatched', Jar) { dependsOn patchJDT archiveClassifier = 'fatjar' manifest = jar.manifest - + from(zipTree(patchJDT.output)) from(sourceSets.main.output) { duplicatesStrategy = DuplicatesStrategy.EXCLUDE } - + from { configurations.shadow.collect { it.isDirectory() ? it : zipTree(it) } } { duplicatesStrategy = DuplicatesStrategy.EXCLUDE } exclude('META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'module-info.class') } -license { - header = file('LICENSE-header.txt') - include 'net/minecraftforge/' -} - -import java.util.zip.* -import org.objectweb.asm.* -import org.objectweb.asm.tree.* - -//TODO: Eclipse complains about unused messages. Find a way to make it shut up. -abstract class PatchJDTClasses extends DefaultTask { - static def COMPILATION_UNIT_RESOLVER = 'org/eclipse/jdt/core/dom/CompilationUnitResolver' - static def RANGE_EXTRACTOR = 'net/minecraftforge/srg2source/extract/RangeExtractor' - static def RESOLVE_METHOD = 'resolve([Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Lorg/eclipse/jdt/core/dom/FileASTRequestor;ILjava/util/Map;I)V' - static def GET_CONTENTS = 'org/eclipse/jdt/internal/compiler/util/Util.getFileCharContent(Ljava/io/File;Ljava/lang/String;)[C' - static def HOOK_DESC_RESOLVE = '(Ljava/lang/String;Ljava/lang/String;)[C' - - @Input abstract SetProperty getTargets() - @InputFiles @Classpath abstract ConfigurableFileCollection getLibraries() - @OutputFile abstract RegularFileProperty getOutput() - - @TaskAction - void patchClass() { - def toProcess = targets.get().collect() - new ZipOutputStream(new FileOutputStream(output.get().getAsFile())).withCloseable{ zout -> - libraries.getFiles().stream().filter{ !it.isDirectory() }.each { lib -> - new ZipFile(lib).withCloseable { zin -> - def remove = [] - toProcess.each{ target -> - def entry = zin.getEntry(target+'.class') - if (entry == null) - return - - def node = new ClassNode() - def reader = new ClassReader(zin.getInputStream(entry)) - reader.accept(node, 0) - - //CompilationUnitResolver allows batch compiling, the problem is it is hardcoded to read the contents from a File. - //So we patch this call to redirect to us, so we can get the contents from our InputSupplier - if (COMPILATION_UNIT_RESOLVER.equals(target)) { - logger.lifecycle('Transforming: ' + target + ' From: ' + lib) - def resolve = node.methods.find{ RESOLVE_METHOD.equals(it.name + it.desc) } - if (resolve == null) - throw new RuntimeException('Failed to patch ' + target + ': Could not find method ' + RESOLVE_METHOD) - for (int x = 0; x < resolve.instructions.size(); x++) { - def insn = resolve.instructions.get(x) - if (insn.type == AbstractInsnNode.METHOD_INSN) { - if (GET_CONTENTS.equals(insn.owner + '.' + insn.name + insn.desc)) { - if ( - resolve.instructions.get(x - 5).opcode == Opcodes.NEW && - resolve.instructions.get(x - 4).opcode == Opcodes.DUP && - resolve.instructions.get(x - 3).opcode == Opcodes.ALOAD && - resolve.instructions.get(x - 2).opcode == Opcodes.INVOKESPECIAL && - resolve.instructions.get(x - 1).opcode == Opcodes.ALOAD - ) { - resolve.instructions.set(resolve.instructions.get(x - 5), new InsnNode(Opcodes.NOP)); // NEW File - resolve.instructions.set(resolve.instructions.get(x - 4), new InsnNode(Opcodes.NOP)); // DUP - resolve.instructions.set(resolve.instructions.get(x - 2), new InsnNode(Opcodes.NOP)); // INVOKESTATIC - insn.owner = RANGE_EXTRACTOR - insn.desc = HOOK_DESC_RESOLVE - //logger.lifecycle('Patched ' + node.name) - remove.add(target) - } else { - throw new IllegalStateException('Found Util.getFileCharContents call, with unexpected context') - } - } - } - } - } else if (RANGE_EXTRACTOR.equals(target)) { - logger.lifecycle('Tansforming: ' + target + ' From: ' + lib) - def marker = node.methods.find{ 'hasBeenASMPatched()Z'.equals(it.name + it.desc) } - if (marker == null) - throw new RuntimeException('Failed to patch ' + target + ': Could not find method hasBeenASMPatched()Z') - marker.instructions.clear() - marker.instructions.add(new InsnNode(Opcodes.ICONST_1)) - marker.instructions.add(new InsnNode(Opcodes.IRETURN)) - //logger.lifecycle('Patched: ' + node.name) - remove.add(target) - } - - def writer = new ClassWriter(0) - node.accept(writer) - - def nentry = new ZipEntry(entry.name) - nentry.time = 0 - zout.putNextEntry(nentry) - zout.write(writer.toByteArray()) - zout.closeEntry() - } - toProcess.removeAll(remove) - } - } - if (!toProcess.isEmpty()) - throw new IllegalStateException('Patching class failed: ' + toProcess) - } - } -} - -tasks.register('unpatchedJar', Jar).configure { +tasks.register('unpatchedJar', Jar) { from sourceSets.main.output archiveClassifier = 'unpatched' } -tasks.register('patchJDT', PatchJDTClasses).configure { - targets.add(PatchJDTClasses.COMPILATION_UNIT_RESOLVER) - targets.add(PatchJDTClasses.RANGE_EXTRACTOR) - libraries.from(unpatchedJar.archiveFile) - libraries.from(configurations.shadow.filter{ !it.isDirectory() }) - output = project.layout.buildDirectory.file("patch_jdt.jar") +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation + options.warnings = false // Shutup deprecated for removal warnings } publishing { @@ -205,17 +106,23 @@ publishing { artifact jar artifact shadowJarPatched artifact sourcesJar - pom { - name = 'Srg2Source' - description = 'Srg2Source library for ForgeGradle' - url = 'https://github.com/MinecraftForge/Srg2Source' - gradleutils.pom.setGitHubDetails(pom, 'Srg2Source') + // TODO [Srg2Source] Enable this. Previous builds have the project.name as the artifact ID + // For now it is disabled until we want to lowercase the artifact ID + //artifactId = projectArtifactId + + pom { pom -> + name = projectDisplayName + description = project.description + + gradleutils.pom.setGitHubDetails pom - license gradleutils.pom.Licenses.LGPLv2_1 + licenses { + license gradleutils.pom.licenses.LGPLv2_1 + } developers { - developer gradleutils.pom.Developers.LexManos + developer gradleutils.pom.developers.LexManos } } } @@ -224,40 +131,3 @@ publishing { maven gradleutils.publishingForgeMaven } } -// We need to write the manifest to the binary file so we have properly versioned packaged at dev time. -tasks.register('writeManifest') { - doLast { - if (plugins.findPlugin('net.minecraftforge.gradle.patcher')) // Forge project - universalJar.manifest.writeTo(rootProject.file('src/main/resources/META-INF/MANIFEST.MF')) - else - jar.manifest.writeTo(project.file('src/main/resources/META-INF/MANIFEST.MF')) - } -} - -tasks.register('generateResources') { - dependsOn('writeManifest') -} - -// Make sure out manifests get written before compiling the code, IDEA calls this task if you tell it to use the gradle build. -tasks.withType(JavaCompile).configureEach { - dependsOn 'generateResources' - dependsOn 'processResources' // Needed because we merge the output of this with the output of the compile task. And gradle detects downstream tasks using the output without a hard dep - options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation - options.warnings = false // Shutup deprecated for removal warnings -} - -// Merge the resources and classes into the same directory. We'll need to split them at runtime because -// Minecraft and Forge are in the same sourceSet as they are inter dependent.. for now.. -sourceSets.each { - def dir = layout.buildDirectory.dir("classes/java/$it.name") - it.output.resourcesDir = dir - it.java.destinationDirectory = dir -} - -eclipse { - // Run everytime eclipse builds the code - //autoBuildTasks writeManifest - // Run when importing the project - synchronizationTasks generateResources, writeManifest -} - diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 0000000..32c26a0 --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,15 @@ +plugins { + id 'java-gradle-plugin' + id 'groovy' + alias libs.plugins.licenser +} + +license { + header = rootProject.file('../LICENSE-header.txt') + newLine = false + exclude '**/*.properties' +} + +dependencies { + implementation libs.bundles.asm +} diff --git a/buildSrc/settings.gradle b/buildSrc/settings.gradle new file mode 100644 index 0000000..46685be --- /dev/null +++ b/buildSrc/settings.gradle @@ -0,0 +1,14 @@ +dependencyResolutionManagement { + repositories { + mavenCentral() + } + + versionCatalogs.register('libs') { + plugin 'licenser', 'net.minecraftforge.licenser' version '1.2.0' + + version('asm', '9.7.1') + library('asm', 'org.ow2.asm', 'asm' ).versionRef('asm') + library('asm-tree', 'org.ow2.asm', 'asm-tree').versionRef('asm') + bundle('asm', ['asm', 'asm-tree']) + } +} diff --git a/buildSrc/src/main/groovy/PatchJDTClasses.groovy b/buildSrc/src/main/groovy/PatchJDTClasses.groovy new file mode 100644 index 0000000..e19f86a --- /dev/null +++ b/buildSrc/src/main/groovy/PatchJDTClasses.groovy @@ -0,0 +1,121 @@ +/* + * Copyright (c) Forge Development LLC + * SPDX-License-Identifier: LGPL-2.1-only + */ +import groovy.transform.CompileStatic +import org.gradle.api.DefaultTask +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.SetProperty +import org.gradle.api.tasks.Classpath +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction +import org.objectweb.asm.ClassReader +import org.objectweb.asm.ClassWriter +import org.objectweb.asm.Opcodes +import org.objectweb.asm.tree.AbstractInsnNode +import org.objectweb.asm.tree.ClassNode +import org.objectweb.asm.tree.InsnNode +import org.objectweb.asm.tree.MethodInsnNode + +import java.util.zip.ZipEntry +import java.util.zip.ZipFile +import java.util.zip.ZipOutputStream + +//TODO: Eclipse complains about unused messages. Find a way to make it shut up. +@CompileStatic +abstract class PatchJDTClasses extends DefaultTask { + public static final String COMPILATION_UNIT_RESOLVER = 'org/eclipse/jdt/core/dom/CompilationUnitResolver' + public static final String RANGE_EXTRACTOR = 'net/minecraftforge/srg2source/extract/RangeExtractor' + public static final String RESOLVE_METHOD = 'resolve([Ljava/lang/String[Ljava/lang/String[Ljava/lang/StringLorg/eclipse/jdt/core/dom/FileASTRequestorILjava/util/MapI)V' + public static final String GET_CONTENTS = 'org/eclipse/jdt/internal/compiler/util/Util.getFileCharContent(Ljava/io/FileLjava/lang/String)[C' + public static final String HOOK_DESC_RESOLVE = '(Ljava/lang/StringLjava/lang/String)[C' + + abstract @Input SetProperty getTargets() + abstract @InputFiles @Classpath ConfigurableFileCollection getLibraries() + abstract @OutputFile RegularFileProperty getOutput() + + @TaskAction + void patchClass() { + final targets = this.targets.get().collect() + try (var zout = new ZipOutputStream(new FileOutputStream(this.output.get().asFile))) { + for (var lib in this.libraries.files.findAll { !it.directory }) { + try (var zin = new ZipFile(lib)) { + def remove = [] + for (var target in targets) { + var entry = zin.getEntry(target + '.class') + if (entry === null) return + + var node = new ClassNode() + var reader = new ClassReader(zin.getInputStream(entry)) + reader.accept(node, 0) + + //CompilationUnitResolver allows batch compiling, the problem is it is hardcoded to read the contents from a File. + //So we patch this call to redirect to us, so we can get the contents from our InputSupplier + if (COMPILATION_UNIT_RESOLVER == target) { + this.logger.lifecycle('Transforming: {} From: {}', target, lib) + var resolve = node.methods.find { RESOLVE_METHOD.equals(it.name + it.desc) } + if (resolve == null) + throw new RuntimeException('Failed to patch ' + target + ': Could not find method ' + RESOLVE_METHOD) + + for (int x = 0; x < resolve.instructions.size(); x++) { + def insn = resolve.instructions.get(x) + if (insn.type != AbstractInsnNode.METHOD_INSN) continue + + insn = insn as MethodInsnNode + if (GET_CONTENTS != "${insn.owner}.${insn.name}${insn.desc}") continue + + if ( + resolve.instructions.get(x - 5).opcode === Opcodes.NEW && + resolve.instructions.get(x - 4).opcode === Opcodes.DUP && + resolve.instructions.get(x - 3).opcode === Opcodes.ALOAD && + resolve.instructions.get(x - 2).opcode === Opcodes.INVOKESPECIAL && + resolve.instructions.get(x - 1).opcode === Opcodes.ALOAD + ) { + resolve.instructions.set(resolve.instructions.get(x - 5), new InsnNode(Opcodes.NOP)) + // NEW File + resolve.instructions.set(resolve.instructions.get(x - 4), new InsnNode(Opcodes.NOP)) + // DUP + resolve.instructions.set(resolve.instructions.get(x - 2), new InsnNode(Opcodes.NOP)) + // INVOKESTATIC + insn.owner = RANGE_EXTRACTOR + insn.desc = HOOK_DESC_RESOLVE + //logger.lifecycle('Patched {}', node.name) + remove.add(target) + } else { + throw new IllegalStateException('Found Util.getFileCharContents call, with unexpected context') + } + } + } else if (RANGE_EXTRACTOR == target) { + this.logger.lifecycle('Tansforming: {} From: {}', target, lib) + def marker = node.methods.find { 'hasBeenASMPatched()Z' == it.name + it.desc } + if (marker == null) + throw new RuntimeException('Failed to patch ' + target + ': Could not find method hasBeenASMPatched()Z') + + marker.instructions.clear() + marker.instructions.add(new InsnNode(Opcodes.ICONST_1)) + marker.instructions.add(new InsnNode(Opcodes.IRETURN)) + //logger.lifecycle('Patched: {}', node.name) + remove.add(target) + } + + def writer = new ClassWriter(0) + node.accept(writer) + + def nentry = new ZipEntry(entry.name) + nentry.time = 0 + zout.putNextEntry(nentry) + zout.write(writer.toByteArray()) + zout.closeEntry() + } + targets.removeAll(remove) + } + } + + if (!targets.empty) + throw new IllegalStateException('Patching class failed: ' + targets) + } + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e644113..9bbc975 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37f853b..d4081da 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a4..faf9300 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # 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 +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -203,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. diff --git a/gradlew.bat b/gradlew.bat index 25da30d..9d21a21 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/settings.gradle b/settings.gradle index 168c004..ebe77d1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,45 +6,52 @@ pluginManagement { } plugins { - id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0' + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.10.0' } dependencyResolutionManagement { - versionCatalogs { - libs { - // Main - library('jopt-simple', 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3') - library('securemodules', 'net.minecraftforge:securemodules:2.2.21') - library('srgutils', 'net.minecraftforge:srgutils:0.5.11') - library('nulls', 'org.jetbrains:annotations:26.0.2') // Got to have our null annotations! - - library('eclipse-jdt', 'org.eclipse.jdt:org.eclipse.jdt.core:3.40.0') - library('eclipse-runtime', 'org.eclipse.platform:org.eclipse.core.runtime:3.32.0') - library('eclipse-resources', 'org.eclipse.platform:org.eclipse.core.resources:3.22.0') - library('eclipse-jobs', 'org.eclipse.platform:org.eclipse.core.jobs:3.15.400') - library('eclipse-types', 'org.eclipse.platform:org.eclipse.core.contenttype:3.9.600') - bundle('eclipse', ['eclipse-jdt', 'eclipse-runtime', 'eclipse-resources', 'eclipse-jobs', 'eclipse-types']) - - // Test - library('ml', 'net.minecraftforge:modlauncher:10.1.4') - library('jimfs', 'com.google.jimfs:jimfs:1.3.0') - - version('junit', '5.12.0') - library('junit-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit') - library('junit-engine', 'org.junit.jupiter', 'junit-jupiter-engine').versionRef('junit') - library('junit-platform-launcher', 'org.junit.platform:junit-platform-launcher:1.12.0') - bundle('junit-runtime', ['junit-engine', 'junit-platform-launcher']) - - version('asm', '9.7.1') - library('asm', 'org.ow2.asm', 'asm' ).versionRef('asm') - library('asm-tree', 'org.ow2.asm', 'asm-tree').versionRef('asm') - bundle('asm', ['asm', 'asm-tree']) - - version('powermock', '2.0.9') - library('powermock-core', 'org.powermock', 'powermock-core').versionRef('powermock') - library('powermock-reflect', 'org.powermock', 'powermock-reflect').versionRef('powermock') - bundle('powermock', ['powermock-core', 'powermock-reflect']) - } + repositories { + mavenCentral() + maven { url = 'https://maven.minecraftforge.net' } + } + + versionCatalogs.register('libs') { + plugin 'licenser', 'net.minecraftforge.licenser' version '1.2.0' + plugin 'gradleutils', 'net.minecraftforge.gradleutils' version '2.6.0' + plugin 'versions', 'com.github.ben-manes.versions' version '0.52.0' + + // Main + library('jopt-simple', 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3') + library('securemodules', 'net.minecraftforge:securemodules:2.2.21') + library('srgutils', 'net.minecraftforge:srgutils:0.5.11') + library('nulls', 'org.jetbrains:annotations:26.0.2') // Got to have our null annotations! + + library('eclipse-jdt', 'org.eclipse.jdt:org.eclipse.jdt.core:3.40.0') + library('eclipse-runtime', 'org.eclipse.platform:org.eclipse.core.runtime:3.32.0') + library('eclipse-resources', 'org.eclipse.platform:org.eclipse.core.resources:3.22.0') + library('eclipse-jobs', 'org.eclipse.platform:org.eclipse.core.jobs:3.15.400') + library('eclipse-types', 'org.eclipse.platform:org.eclipse.core.contenttype:3.9.600') + bundle('eclipse', ['eclipse-jdt', 'eclipse-runtime', 'eclipse-resources', 'eclipse-jobs', 'eclipse-types']) + + // Test + library('ml', 'net.minecraftforge:modlauncher:10.1.4') + library('jimfs', 'com.google.jimfs:jimfs:1.3.0') + + version('junit', '5.12.0') + library('junit-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit') + library('junit-engine', 'org.junit.jupiter', 'junit-jupiter-engine').versionRef('junit') + library('junit-platform-launcher', 'org.junit.platform:junit-platform-launcher:1.12.0') + bundle('junit-runtime', ['junit-engine', 'junit-platform-launcher']) + + version('asm', '9.7.1') + library('asm', 'org.ow2.asm', 'asm' ).versionRef('asm') + library('asm-tree', 'org.ow2.asm', 'asm-tree').versionRef('asm') + bundle('asm', ['asm', 'asm-tree']) + + version('powermock', '2.0.9') + library('powermock-core', 'org.powermock', 'powermock-core').versionRef('powermock') + library('powermock-reflect', 'org.powermock', 'powermock-reflect').versionRef('powermock') + bundle('powermock', ['powermock-core', 'powermock-reflect']) } }