mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-04-01 21:17:46 -05:00
Merge remote-tracking branch 'upstream/exp/1.3' into exp/1.3
# Conflicts: # build.gradle # src/main/java/net/fabricmc/loom/LoomGradleExtension.java # src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java # src/main/java/net/fabricmc/loom/configuration/decompile/SingleJarDecompileConfiguration.java # src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftJarConfiguration.java # src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.java # src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/IntermediaryMinecraftProvider.java # src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/NamedMinecraftProvider.java # src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java
This commit is contained in:
16
build.gradle
16
build.gradle
@@ -8,7 +8,7 @@ plugins {
|
||||
id 'checkstyle'
|
||||
id 'jacoco'
|
||||
id 'codenarc'
|
||||
id "org.jetbrains.kotlin.jvm" version "1.8.0" // Must match the version included with gradle.
|
||||
alias(libs.plugins.kotlin)
|
||||
id "com.diffplug.spotless" version "6.18.0"
|
||||
id "org.gradle.test-retry" version "1.5.2"
|
||||
}
|
||||
@@ -25,7 +25,7 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
|
||||
|
||||
group = "dev.architectury"
|
||||
archivesBaseName = project.name
|
||||
def baseVersion = '1.2'
|
||||
def baseVersion = '1.3'
|
||||
|
||||
def ENV = System.getenv()
|
||||
def runNumber = ENV.GITHUB_RUN_NUMBER ?: "9999"
|
||||
@@ -40,6 +40,12 @@ if (!isSnapshot) {
|
||||
|
||||
logger.lifecycle(":building plugin v${version}")
|
||||
|
||||
// We must build against the version of Kotlin Gradle ships with.
|
||||
def kotlinVersion = KotlinDslVersion.current().getKotlinVersion()
|
||||
if (libs.versions.kotlin.get() != kotlinVersion) {
|
||||
throw new IllegalStateException("Requires Kotlin version: ${kotlinVersion}")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url "https://maven.fabricmc.net/" }
|
||||
@@ -103,7 +109,7 @@ dependencies {
|
||||
|
||||
// decompilers
|
||||
implementation ('net.fabricmc:fabric-fernflower:2.0.0')
|
||||
implementation ('net.fabricmc:cfr:0.2.0')
|
||||
implementation ('net.fabricmc:cfr:0.2.1')
|
||||
|
||||
// source code remapping
|
||||
implementation ('dev.architectury:mercury:0.1.2.15')
|
||||
@@ -114,7 +120,7 @@ dependencies {
|
||||
}
|
||||
|
||||
// Kapt integration
|
||||
compileOnly('org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0') // Must match the version included with gradle.
|
||||
compileOnly libs.kotlin.gradle.plugin
|
||||
|
||||
// Forge patches
|
||||
implementation ('net.minecraftforge:installertools:1.2.0')
|
||||
@@ -137,6 +143,7 @@ dependencies {
|
||||
exclude group: 'org.jetbrains.kotlin'
|
||||
}
|
||||
testImplementation 'org.mockito:mockito-core:5.2.0'
|
||||
testImplementation 'com.microsoft.java:com.microsoft.java.debug.core:0.46.0'
|
||||
|
||||
compileOnly 'org.jetbrains:annotations:24.0.1'
|
||||
testCompileOnly 'org.jetbrains:annotations:24.0.1'
|
||||
@@ -245,6 +252,7 @@ test {
|
||||
}
|
||||
}
|
||||
|
||||
import org.gradle.launcher.cli.KotlinDslVersion
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.w3c.dom.Document
|
||||
import org.w3c.dom.Element
|
||||
|
||||
8
gradle/libs.versions.toml
Normal file
8
gradle/libs.versions.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
[versions]
|
||||
kotlin = "1.8.10"
|
||||
|
||||
[libraries]
|
||||
kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
|
||||
[plugins]
|
||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
@@ -30,6 +30,8 @@ import java.util.List;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.fabricmc.loom.api.LoomGradleExtensionAPI;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
@@ -46,6 +48,7 @@ import net.fabricmc.loom.configuration.providers.forge.SrgProvider;
|
||||
import net.fabricmc.loom.configuration.providers.forge.mcpconfig.McpConfigProvider;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessorManager;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.SrgMinecraftProvider;
|
||||
@@ -54,6 +57,7 @@ import net.fabricmc.loom.extension.MixinExtension;
|
||||
import net.fabricmc.loom.util.ModPlatform;
|
||||
import net.fabricmc.loom.util.download.DownloadBuilder;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public interface LoomGradleExtension extends LoomGradleExtensionAPI {
|
||||
static LoomGradleExtension get(Project project) {
|
||||
return (LoomGradleExtension) project.getExtensions().getByName("loom");
|
||||
@@ -128,6 +132,8 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI {
|
||||
*/
|
||||
boolean multiProjectOptimisation();
|
||||
|
||||
ListProperty<LibraryProcessorManager.LibraryProcessorFactory> getLibraryProcessors();
|
||||
|
||||
// ===================
|
||||
// Architectury Loom
|
||||
// ===================
|
||||
|
||||
@@ -70,6 +70,7 @@ import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.AbstractMappedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.SrgMinecraftProvider;
|
||||
@@ -219,8 +220,8 @@ public abstract class CompileConfiguration implements Runnable {
|
||||
}
|
||||
|
||||
// Provide the remapped mc jars
|
||||
final IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider = jarConfiguration.getIntermediaryMinecraftProviderBiFunction().apply(configContext, minecraftProvider);
|
||||
NamedMinecraftProvider<?> namedMinecraftProvider = jarConfiguration.getNamedMinecraftProviderBiFunction().apply(configContext, minecraftProvider);
|
||||
final IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider = jarConfiguration.getIntermediaryMinecraftProviderBiFunction().apply(project, minecraftProvider);
|
||||
NamedMinecraftProvider<?> namedMinecraftProvider = jarConfiguration.getNamedMinecraftProviderBiFunction().apply(project, minecraftProvider);
|
||||
|
||||
registerGameProcessors(configContext);
|
||||
MinecraftJarProcessorManager minecraftJarProcessorManager = MinecraftJarProcessorManager.create(getProject());
|
||||
@@ -230,11 +231,13 @@ public abstract class CompileConfiguration implements Runnable {
|
||||
namedMinecraftProvider = jarConfiguration.getProcessedNamedMinecraftProviderBiFunction().apply(namedMinecraftProvider, minecraftJarProcessorManager);
|
||||
}
|
||||
|
||||
final var provideContext = new AbstractMappedMinecraftProvider.ProvideContext(true, extension.refreshDeps(), configContext);
|
||||
|
||||
extension.setIntermediaryMinecraftProvider(intermediaryMinecraftProvider);
|
||||
intermediaryMinecraftProvider.provide(true);
|
||||
intermediaryMinecraftProvider.provide(provideContext);
|
||||
|
||||
extension.setNamedMinecraftProvider(namedMinecraftProvider);
|
||||
namedMinecraftProvider.provide(true);
|
||||
namedMinecraftProvider.provide(provideContext);
|
||||
|
||||
if (extension.isForge()) {
|
||||
final SrgMinecraftProvider<?> srgMinecraftProvider = jarConfiguration.getSrgMinecraftProviderBiFunction().apply(configContext, minecraftProvider);
|
||||
|
||||
@@ -183,7 +183,11 @@ public final class RemapConfigurations {
|
||||
configuration.getTargetConfigurationName().convention(targetConfiguration);
|
||||
configuration.getOnCompileClasspath().convention(compileClasspath);
|
||||
configuration.getOnRuntimeClasspath().convention(runtimeClasspath);
|
||||
configuration.getPublishingMode().convention(publishingMode);
|
||||
|
||||
// Publish only for the main source set.
|
||||
if (SourceSet.MAIN_SOURCE_SET_NAME.equals(sourceSet.getName())) {
|
||||
configuration.getPublishingMode().convention(publishingMode);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -27,13 +27,14 @@ package net.fabricmc.loom.configuration.decompile;
|
||||
import java.io.File;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
import org.gradle.api.artifacts.ConfigurationContainer;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider;
|
||||
import net.fabricmc.loom.task.UnpickJarTask;
|
||||
import net.fabricmc.loom.task.GenerateSourcesTask;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public abstract class DecompileConfiguration<T extends MappedMinecraftProvider> {
|
||||
protected final Project project;
|
||||
@@ -50,11 +51,13 @@ public abstract class DecompileConfiguration<T extends MappedMinecraftProvider>
|
||||
|
||||
public abstract void afterEvaluation();
|
||||
|
||||
protected final TaskProvider<UnpickJarTask> createUnpickJarTask(String name, File inputJar, File outputJar) {
|
||||
return project.getTasks().register(name, UnpickJarTask.class, unpickJarTask -> {
|
||||
unpickJarTask.getUnpickDefinitions().set(mappingConfiguration.getUnpickDefinitionsFile());
|
||||
unpickJarTask.getInputJar().set(inputJar);
|
||||
unpickJarTask.getOutputJar().set(outputJar);
|
||||
});
|
||||
protected final void configureUnpick(GenerateSourcesTask task, File unpickOutputJar) {
|
||||
final ConfigurationContainer configurations = task.getProject().getConfigurations();
|
||||
|
||||
task.getUnpickDefinitions().set(mappingConfiguration.getUnpickDefinitionsFile());
|
||||
task.getUnpickOutputJar().set(unpickOutputJar);
|
||||
task.getUnpickConstantJar().setFrom(configurations.getByName(Constants.Configurations.MAPPING_CONSTANTS));
|
||||
task.getUnpickClasspath().setFrom(configurations.getByName(Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES));
|
||||
task.getUnpickClasspath().from(configurations.getByName(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
package net.fabricmc.loom.configuration.decompile;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.providers.forge.MinecraftPatchedProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider;
|
||||
import net.fabricmc.loom.task.GenerateForgePatchedSourcesTask;
|
||||
@@ -44,36 +44,25 @@ public class SingleJarDecompileConfiguration extends DecompileConfiguration<Mapp
|
||||
|
||||
@Override
|
||||
public final void afterEvaluation() {
|
||||
List<Path> minecraftJars = minecraftProvider.getMinecraftJarPaths();
|
||||
final List<MinecraftJar> minecraftJars = minecraftProvider.getMinecraftJars();
|
||||
assert minecraftJars.size() == 1;
|
||||
|
||||
final File namedJar = minecraftJars.get(0).toFile();
|
||||
|
||||
File mappedJar = namedJar;
|
||||
|
||||
if (mappingConfiguration.hasUnpickDefinitions()) {
|
||||
File outputJar = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-unpicked.jar");
|
||||
createUnpickJarTask("unpickJar", namedJar, outputJar);
|
||||
|
||||
mappedJar = outputJar;
|
||||
}
|
||||
|
||||
final File inputJar = mappedJar;
|
||||
final MinecraftJar minecraftJar = minecraftJars.get(0);
|
||||
|
||||
LoomGradleExtension.get(project).getDecompilerOptions().forEach(options -> {
|
||||
final String decompilerName = options.getFormattedName();
|
||||
String taskName = "genSourcesWith" + decompilerName;
|
||||
// Decompiler will be passed to the constructor of GenerateSourcesTask
|
||||
project.getTasks().register(taskName, GenerateSourcesTask.class, options).configure(task -> {
|
||||
task.getInputJar().set(inputJar);
|
||||
task.getRuntimeJar().set(namedJar);
|
||||
task.getInputJarName().set(minecraftJar.getName());
|
||||
task.getOutputJar().fileValue(GenerateSourcesTask.getMappedJarFileWithSuffix("-sources.jar", minecraftJar.getPath()));
|
||||
|
||||
task.dependsOn(project.getTasks().named("validateAccessWidener"));
|
||||
task.setDescription("Decompile minecraft using %s.".formatted(decompilerName));
|
||||
task.setGroup(Constants.TaskGroup.FABRIC);
|
||||
|
||||
if (mappingConfiguration.hasUnpickDefinitions()) {
|
||||
task.dependsOn(project.getTasks().named("unpickJar"));
|
||||
final File outputJar = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-unpicked.jar");
|
||||
configureUnpick(task, outputJar);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -32,9 +32,9 @@ import org.gradle.api.tasks.TaskProvider;
|
||||
|
||||
import net.fabricmc.loom.api.decompilers.DecompilerOptions;
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider;
|
||||
import net.fabricmc.loom.task.GenerateSourcesTask;
|
||||
import net.fabricmc.loom.task.UnpickJarTask;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public final class SplitDecompileConfiguration extends DecompileConfiguration<MappedMinecraftProvider.Split> {
|
||||
@@ -44,41 +44,26 @@ public final class SplitDecompileConfiguration extends DecompileConfiguration<Ma
|
||||
|
||||
@Override
|
||||
public void afterEvaluation() {
|
||||
File commonJarToDecompile = minecraftProvider.getCommonJar().toFile();
|
||||
File clientOnlyJarToDecompile = minecraftProvider.getClientOnlyJar().toFile();
|
||||
|
||||
TaskProvider<UnpickJarTask> unpickCommonJar = null;
|
||||
TaskProvider<UnpickJarTask> unpickClientOnlyJar = null;
|
||||
|
||||
if (mappingConfiguration.hasUnpickDefinitions()) {
|
||||
commonJarToDecompile = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-common-unpicked.jar");
|
||||
clientOnlyJarToDecompile = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-clientonly-unpicked.jar");
|
||||
|
||||
unpickCommonJar = createUnpickJarTask("unpickCommonJar", minecraftProvider.getCommonJar().toFile(), commonJarToDecompile);
|
||||
unpickClientOnlyJar = createUnpickJarTask("unpickClientOnlyJar", minecraftProvider.getClientOnlyJar().toFile(), clientOnlyJarToDecompile);
|
||||
}
|
||||
|
||||
// Need to re-declare them as final to access them from the lambada
|
||||
final File commonJar = commonJarToDecompile;
|
||||
final File clientOnlyJar = clientOnlyJarToDecompile;
|
||||
final TaskProvider<UnpickJarTask> unpickCommonJarTask = unpickCommonJar;
|
||||
final TaskProvider<UnpickJarTask> unpickClientOnlyJarTask = unpickClientOnlyJar;
|
||||
final MinecraftJar commonJar = minecraftProvider.getCommonJar();
|
||||
final MinecraftJar clientOnlyJar = minecraftProvider.getClientOnlyJar();
|
||||
|
||||
final TaskProvider<Task> commonDecompileTask = createDecompileTasks("Common", task -> {
|
||||
task.getInputJar().set(commonJar);
|
||||
task.getRuntimeJar().set(minecraftProvider.getCommonJar().toFile());
|
||||
task.getInputJarName().set(commonJar.getName());
|
||||
task.getOutputJar().fileValue(GenerateSourcesTask.getMappedJarFileWithSuffix("-sources.jar", commonJar.getPath()));
|
||||
|
||||
if (unpickCommonJarTask != null) {
|
||||
task.dependsOn(unpickCommonJarTask);
|
||||
if (mappingConfiguration.hasUnpickDefinitions()) {
|
||||
File unpickJar = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-common-unpicked.jar");
|
||||
configureUnpick(task, unpickJar);
|
||||
}
|
||||
});
|
||||
|
||||
final TaskProvider<Task> clientOnlyDecompileTask = createDecompileTasks("ClientOnly", task -> {
|
||||
task.getInputJar().set(clientOnlyJar);
|
||||
task.getRuntimeJar().set(minecraftProvider.getClientOnlyJar().toFile());
|
||||
task.getInputJarName().set(clientOnlyJar.getName());
|
||||
task.getOutputJar().fileValue(GenerateSourcesTask.getMappedJarFileWithSuffix("-sources.jar", clientOnlyJar.getPath()));
|
||||
|
||||
if (unpickCommonJarTask != null) {
|
||||
task.dependsOn(unpickClientOnlyJarTask);
|
||||
if (mappingConfiguration.hasUnpickDefinitions()) {
|
||||
File unpickJar = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-clientonly-unpicked.jar");
|
||||
configureUnpick(task, unpickJar);
|
||||
}
|
||||
|
||||
// Don't allow them to run at the same time.
|
||||
|
||||
@@ -55,6 +55,6 @@ public class IdeaUtils {
|
||||
module = project.getName() + "." + module;
|
||||
}
|
||||
|
||||
return module;
|
||||
return module.replace(' ', '_');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -44,6 +45,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -174,14 +176,20 @@ public abstract class InterfaceInjectionProcessor implements MinecraftJarProcess
|
||||
}
|
||||
|
||||
private static String appendComment(String comment, List<InjectedInterface> injectedInterfaces) {
|
||||
for (InjectedInterface injectedInterface : injectedInterfaces) {
|
||||
String iiComment = "Interface {@link %s} injected by mod %s".formatted(injectedInterface.ifaceName.substring(injectedInterface.ifaceName.lastIndexOf("/") + 1), injectedInterface.modId);
|
||||
if (injectedInterfaces.isEmpty()) {
|
||||
return comment;
|
||||
}
|
||||
|
||||
if (comment == null || !comment.contains(iiComment)) {
|
||||
if (comment == null) {
|
||||
comment = iiComment;
|
||||
var commentBuilder = comment == null ? new StringBuilder() : new StringBuilder(comment);
|
||||
|
||||
for (InjectedInterface injectedInterface : injectedInterfaces) {
|
||||
String iiComment = "<p>Interface {@link %s} injected by mod %s</p>".formatted(injectedInterface.ifaceName().replace('/', '.').replace('$', '.'), injectedInterface.modId());
|
||||
|
||||
if (commentBuilder.indexOf(iiComment) == -1) {
|
||||
if (commentBuilder.isEmpty()) {
|
||||
commentBuilder.append(iiComment);
|
||||
} else {
|
||||
comment += "\n" + iiComment;
|
||||
commentBuilder.append('\n').append(iiComment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,7 +234,10 @@ public abstract class InterfaceInjectionProcessor implements MinecraftJarProcess
|
||||
}
|
||||
|
||||
private static class InjectingClassVisitor extends ClassVisitor {
|
||||
private static final int INTERFACE_ACCESS = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE;
|
||||
|
||||
private final List<InjectedInterface> injectedInterfaces;
|
||||
private final Set<String> knownInnerClasses = new HashSet<>();
|
||||
|
||||
InjectingClassVisitor(int asmVersion, ClassWriter writer, List<InjectedInterface> injectedInterfaces) {
|
||||
super(asmVersion, writer);
|
||||
@@ -259,5 +270,53 @@ public abstract class InterfaceInjectionProcessor implements MinecraftJarProcess
|
||||
|
||||
super.visit(version, access, name, signature, superName, modifiedInterfaces.toArray(new String[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClass(final String name, final String outerName, final String innerName, final int access) {
|
||||
this.knownInnerClasses.add(name);
|
||||
super.visitInnerClass(name, outerName, innerName, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
// inject any necessary inner class entries
|
||||
// this may produce technically incorrect bytecode cuz we don't know the actual access flags for inner class entries
|
||||
// but it's hopefully enough to quiet some IDE errors
|
||||
for (final InjectedInterface itf : injectedInterfaces) {
|
||||
if (this.knownInnerClasses.contains(itf.ifaceName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int simpleNameIdx = itf.ifaceName().lastIndexOf('/');
|
||||
final String simpleName = simpleNameIdx == -1 ? itf.ifaceName() : itf.ifaceName().substring(simpleNameIdx + 1);
|
||||
int lastIdx = -1;
|
||||
int dollarIdx = -1;
|
||||
|
||||
// Iterate through inner class entries starting from outermost to innermost
|
||||
while ((dollarIdx = simpleName.indexOf('$', dollarIdx + 1)) != -1) {
|
||||
if (dollarIdx - lastIdx == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Emit the inner class entry from this to the last one
|
||||
if (lastIdx != -1) {
|
||||
final String outerName = itf.ifaceName().substring(0, simpleNameIdx + 1 + lastIdx);
|
||||
final String innerName = simpleName.substring(lastIdx + 1, dollarIdx);
|
||||
super.visitInnerClass(outerName + '$' + innerName, outerName, innerName, INTERFACE_ACCESS);
|
||||
}
|
||||
|
||||
lastIdx = dollarIdx;
|
||||
}
|
||||
|
||||
// If we have a trailer to append
|
||||
if (lastIdx != -1 && lastIdx != simpleName.length()) {
|
||||
final String outerName = itf.ifaceName().substring(0, simpleNameIdx + 1 + lastIdx);
|
||||
final String innerName = simpleName.substring(lastIdx + 1);
|
||||
super.visitInnerClass(outerName + '$' + innerName, outerName, innerName, INTERFACE_ACCESS);
|
||||
}
|
||||
}
|
||||
|
||||
super.visitEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,18 @@ package net.fabricmc.loom.configuration.providers.minecraft;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public record ManifestVersion(List<Versions> versions, Map<String, String> latest) {
|
||||
public static class Versions {
|
||||
public String id, url, sha1;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Versions getVersion(String id) {
|
||||
return versions.stream()
|
||||
.filter(versions -> versions.id.equalsIgnoreCase(id))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.decompile.DecompileConfiguration;
|
||||
import net.fabricmc.loom.configuration.decompile.SingleJarDecompileConfiguration;
|
||||
@@ -79,8 +81,8 @@ public enum MinecraftJarConfiguration {
|
||||
);
|
||||
|
||||
private final Function<ConfigContext, MinecraftProvider> minecraftProviderFunction;
|
||||
private final BiFunction<ConfigContext, MinecraftProvider, IntermediaryMinecraftProvider<?>> intermediaryMinecraftProviderBiFunction;
|
||||
private final BiFunction<ConfigContext, MinecraftProvider, NamedMinecraftProvider<?>> namedMinecraftProviderBiFunction;
|
||||
private final BiFunction<Project, MinecraftProvider, IntermediaryMinecraftProvider<?>> intermediaryMinecraftProviderBiFunction;
|
||||
private final BiFunction<Project, MinecraftProvider, NamedMinecraftProvider<?>> namedMinecraftProviderBiFunction;
|
||||
private final BiFunction<ConfigContext, MinecraftProvider, SrgMinecraftProvider<?>> srgMinecraftProviderBiFunction;
|
||||
private final BiFunction<NamedMinecraftProvider<?>, MinecraftJarProcessorManager, ProcessedNamedMinecraftProvider<?, ?>> processedNamedMinecraftProviderBiFunction;
|
||||
private final BiFunction<ConfigContext, MappedMinecraftProvider, DecompileConfiguration<?>> decompileConfigurationBiFunction;
|
||||
@@ -89,16 +91,16 @@ public enum MinecraftJarConfiguration {
|
||||
@SuppressWarnings("unchecked") // Just a bit of a generic mess :)
|
||||
<M extends MinecraftProvider, P extends NamedMinecraftProvider<M>, Q extends MappedMinecraftProvider> MinecraftJarConfiguration(
|
||||
Function<ConfigContext, M> minecraftProviderFunction,
|
||||
BiFunction<ConfigContext, M, IntermediaryMinecraftProvider<M>> intermediaryMinecraftProviderBiFunction,
|
||||
BiFunction<ConfigContext, M, P> namedMinecraftProviderBiFunction,
|
||||
BiFunction<Project, M, IntermediaryMinecraftProvider<M>> intermediaryMinecraftProviderBiFunction,
|
||||
BiFunction<Project, M, P> namedMinecraftProviderBiFunction,
|
||||
BiFunction<ConfigContext, M, SrgMinecraftProvider<M>> srgMinecraftProviderBiFunction,
|
||||
BiFunction<P, MinecraftJarProcessorManager, ProcessedNamedMinecraftProvider<M, P>> processedNamedMinecraftProviderBiFunction,
|
||||
BiFunction<ConfigContext, Q, DecompileConfiguration<?>> decompileConfigurationBiFunction,
|
||||
List<String> supportedEnvironments
|
||||
) {
|
||||
this.minecraftProviderFunction = (Function<ConfigContext, MinecraftProvider>) minecraftProviderFunction;
|
||||
this.intermediaryMinecraftProviderBiFunction = (BiFunction<ConfigContext, MinecraftProvider, IntermediaryMinecraftProvider<?>>) (Object) intermediaryMinecraftProviderBiFunction;
|
||||
this.namedMinecraftProviderBiFunction = (BiFunction<ConfigContext, MinecraftProvider, NamedMinecraftProvider<?>>) namedMinecraftProviderBiFunction;
|
||||
this.intermediaryMinecraftProviderBiFunction = (BiFunction<Project, MinecraftProvider, IntermediaryMinecraftProvider<?>>) (Object) intermediaryMinecraftProviderBiFunction;
|
||||
this.namedMinecraftProviderBiFunction = (BiFunction<Project, MinecraftProvider, NamedMinecraftProvider<?>>) namedMinecraftProviderBiFunction;
|
||||
this.srgMinecraftProviderBiFunction = (BiFunction<ConfigContext, MinecraftProvider, SrgMinecraftProvider<?>>) (Object) srgMinecraftProviderBiFunction;
|
||||
this.processedNamedMinecraftProviderBiFunction = (BiFunction<NamedMinecraftProvider<?>, MinecraftJarProcessorManager, ProcessedNamedMinecraftProvider<?, ?>>) (Object) processedNamedMinecraftProviderBiFunction;
|
||||
this.decompileConfigurationBiFunction = (BiFunction<ConfigContext, MappedMinecraftProvider, DecompileConfiguration<?>>) decompileConfigurationBiFunction;
|
||||
@@ -109,11 +111,11 @@ public enum MinecraftJarConfiguration {
|
||||
return minecraftProviderFunction;
|
||||
}
|
||||
|
||||
public BiFunction<ConfigContext, MinecraftProvider, IntermediaryMinecraftProvider<?>> getIntermediaryMinecraftProviderBiFunction() {
|
||||
public BiFunction<Project, MinecraftProvider, IntermediaryMinecraftProvider<?>> getIntermediaryMinecraftProviderBiFunction() {
|
||||
return intermediaryMinecraftProviderBiFunction;
|
||||
}
|
||||
|
||||
public BiFunction<ConfigContext, MinecraftProvider, NamedMinecraftProvider<?>> getNamedMinecraftProviderBiFunction() {
|
||||
public BiFunction<Project, MinecraftProvider, NamedMinecraftProvider<?>> getNamedMinecraftProviderBiFunction() {
|
||||
return namedMinecraftProviderBiFunction;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ public class MinecraftLibraryProvider {
|
||||
public MinecraftLibraryProvider(MinecraftProvider minecraftProvider, Project project) {
|
||||
this.project = project;
|
||||
this.minecraftProvider = minecraftProvider;
|
||||
this.processorManager = new LibraryProcessorManager(platform, project.getRepositories(), getEnabledProcessors());
|
||||
this.processorManager = new LibraryProcessorManager(platform, project.getRepositories(), LoomGradleExtension.get(project).getLibraryProcessors().get(), getEnabledProcessors());
|
||||
}
|
||||
|
||||
private List<String> getEnabledProcessors() {
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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.configuration.providers.minecraft;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.util.MirrorUtil;
|
||||
import net.fabricmc.loom.util.download.DownloadBuilder;
|
||||
|
||||
public final class MinecraftMetadataProvider {
|
||||
private final Options options;
|
||||
private final Function<String, DownloadBuilder> download;
|
||||
|
||||
private ManifestVersion.Versions versionEntry;
|
||||
private MinecraftVersionMeta versionMeta;
|
||||
|
||||
public MinecraftMetadataProvider(Options options, Function<String, DownloadBuilder> download) {
|
||||
this.options = options;
|
||||
this.download = download;
|
||||
}
|
||||
|
||||
public MinecraftVersionMeta getVersionMeta() {
|
||||
try {
|
||||
if (versionEntry == null) {
|
||||
versionEntry = getVersionEntry();
|
||||
}
|
||||
|
||||
if (versionMeta == null) {
|
||||
versionMeta = readVersionMeta();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return versionMeta;
|
||||
}
|
||||
|
||||
private ManifestVersion.Versions getVersionEntry() throws IOException {
|
||||
// Custom URL always takes priority
|
||||
if (options.customManifestUrl() != null) {
|
||||
ManifestVersion.Versions customVersion = new ManifestVersion.Versions();
|
||||
customVersion.id = options.minecraftVersion();
|
||||
customVersion.url = options.customManifestUrl();
|
||||
return customVersion;
|
||||
}
|
||||
|
||||
final List<ManifestVersionSupplier> suppliers = List.of(
|
||||
// First try finding the version with caching
|
||||
() -> getVersions(false),
|
||||
// Then try finding the experimental version with caching
|
||||
() -> getExperimentalVersions(false),
|
||||
// Then force download Mojang's metadata to find the version
|
||||
() -> getVersions(true),
|
||||
// Finally try a force downloaded experimental metadata.
|
||||
() -> getExperimentalVersions(true)
|
||||
);
|
||||
|
||||
for (ManifestVersionSupplier supplier : suppliers) {
|
||||
final ManifestVersion.Versions version = supplier.get().getVersion(options.minecraftVersion());
|
||||
|
||||
if (version != null) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Failed to find minecraft version: " + options.minecraftVersion());
|
||||
}
|
||||
|
||||
private ManifestVersion getVersions(boolean forceDownload) throws IOException {
|
||||
return getVersions(options.versionManifestUrl(), options.versionManifestPath(), forceDownload);
|
||||
}
|
||||
|
||||
private ManifestVersion getExperimentalVersions(boolean forceDownload) throws IOException {
|
||||
return getVersions(options.experimentalVersionManifestUrl(), options.experimentalVersionManifestPath(), forceDownload);
|
||||
}
|
||||
|
||||
private ManifestVersion getVersions(String url, Path cacheFile, boolean forceDownload) throws IOException {
|
||||
DownloadBuilder builder = download.apply(url);
|
||||
|
||||
if (forceDownload) {
|
||||
builder = builder.forceDownload();
|
||||
} else {
|
||||
builder = builder.defaultCache();
|
||||
}
|
||||
|
||||
final String versionManifest = builder.downloadString(cacheFile);
|
||||
return LoomGradlePlugin.OBJECT_MAPPER.readValue(versionManifest, ManifestVersion.class);
|
||||
}
|
||||
|
||||
private MinecraftVersionMeta readVersionMeta() throws IOException {
|
||||
final DownloadBuilder builder = download.apply(versionEntry.url);
|
||||
|
||||
if (versionEntry.sha1 != null) {
|
||||
builder.sha1(versionEntry.sha1);
|
||||
} else {
|
||||
builder.defaultCache();
|
||||
}
|
||||
|
||||
final String json = builder.downloadString(options.minecraftMetadataPath());
|
||||
return LoomGradlePlugin.OBJECT_MAPPER.readValue(json, MinecraftVersionMeta.class);
|
||||
}
|
||||
|
||||
public record Options(String minecraftVersion,
|
||||
String versionManifestUrl,
|
||||
String experimentalVersionManifestUrl,
|
||||
@Nullable String customManifestUrl,
|
||||
Path versionManifestPath,
|
||||
Path experimentalVersionManifestPath,
|
||||
Path minecraftMetadataPath) {
|
||||
public static Options create(String minecraftVersion, Project project, Path minecraftMetadataPath) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final Path userCache = extension.getFiles().getUserCache().toPath();
|
||||
|
||||
return new Options(
|
||||
minecraftVersion,
|
||||
MirrorUtil.getVersionManifests(project),
|
||||
MirrorUtil.getExperimentalVersions(project),
|
||||
extension.getCustomMinecraftManifest().getOrNull(),
|
||||
userCache.resolve("version_manifest.json"),
|
||||
userCache.resolve("experimental_version_manifest.json"),
|
||||
minecraftMetadataPath
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface ManifestVersionSupplier {
|
||||
ManifestVersion get() throws IOException;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@
|
||||
package net.fabricmc.loom.configuration.providers.minecraft;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
@@ -37,25 +36,19 @@ import org.gradle.api.logging.Logger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.DependencyInfo;
|
||||
import net.fabricmc.loom.configuration.providers.BundleMetadata;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.MirrorUtil;
|
||||
import net.fabricmc.loom.util.download.DownloadBuilder;
|
||||
import net.fabricmc.loom.util.download.DownloadExecutor;
|
||||
import net.fabricmc.loom.util.download.GradleDownloadProgressListener;
|
||||
import net.fabricmc.loom.util.gradle.ProgressGroup;
|
||||
|
||||
public abstract class MinecraftProvider {
|
||||
private String minecraftVersion;
|
||||
|
||||
private MinecraftVersionMeta versionInfo;
|
||||
private MinecraftLibraryProvider libraryProvider;
|
||||
private MinecraftMetadataProvider metadataProvider;
|
||||
|
||||
private File workingDir;
|
||||
private File minecraftJson;
|
||||
private File minecraftClientJar;
|
||||
// Note this will be the boostrap jar starting with 21w39a
|
||||
private File minecraftServerJar;
|
||||
@@ -63,8 +56,6 @@ public abstract class MinecraftProvider {
|
||||
private File minecraftExtractedServerJar;
|
||||
@Nullable
|
||||
private BundleMetadata serverBundleMetadata;
|
||||
private File versionManifestJson;
|
||||
private File experimentalVersionsJson;
|
||||
private String jarPrefix = "";
|
||||
|
||||
private final Project project;
|
||||
@@ -91,11 +82,14 @@ public abstract class MinecraftProvider {
|
||||
|
||||
initFiles();
|
||||
|
||||
downloadMcJson();
|
||||
|
||||
try (FileReader reader = new FileReader(minecraftJson)) {
|
||||
versionInfo = LoomGradlePlugin.OBJECT_MAPPER.readValue(reader, MinecraftVersionMeta.class);
|
||||
}
|
||||
metadataProvider = new MinecraftMetadataProvider(
|
||||
MinecraftMetadataProvider.Options.create(
|
||||
minecraftVersion,
|
||||
getProject(),
|
||||
file("minecraft-info.json").toPath()
|
||||
),
|
||||
getExtension()::download
|
||||
);
|
||||
|
||||
downloadJars();
|
||||
|
||||
@@ -103,16 +97,13 @@ public abstract class MinecraftProvider {
|
||||
serverBundleMetadata = BundleMetadata.fromJar(minecraftServerJar.toPath());
|
||||
}
|
||||
|
||||
libraryProvider = new MinecraftLibraryProvider(this, project);
|
||||
final MinecraftLibraryProvider libraryProvider = new MinecraftLibraryProvider(this, project);
|
||||
libraryProvider.provide();
|
||||
}
|
||||
|
||||
protected void initFiles() {
|
||||
workingDir = new File(getExtension().getFiles().getUserCache(), minecraftVersion);
|
||||
workingDir.mkdirs();
|
||||
minecraftJson = file("minecraft-info.json");
|
||||
versionManifestJson = new File(getExtension().getFiles().getUserCache(), "version_manifest.json");
|
||||
experimentalVersionsJson = new File(getExtension().getFiles().getUserCache(), "experimental_version_manifest.json");
|
||||
|
||||
if (provideClient()) {
|
||||
minecraftClientJar = file("minecraft-client.jar");
|
||||
@@ -124,73 +115,11 @@ public abstract class MinecraftProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadMcJson() throws IOException {
|
||||
final String versionManifestUrl = MirrorUtil.getVersionManifests(getProject());
|
||||
final String versionManifest = getExtension().download(versionManifestUrl)
|
||||
.defaultCache()
|
||||
.downloadString(versionManifestJson.toPath());
|
||||
|
||||
final ManifestVersion mcManifest = LoomGradlePlugin.OBJECT_MAPPER.readValue(versionManifest, ManifestVersion.class);
|
||||
ManifestVersion.Versions version = null;
|
||||
|
||||
if (getExtension().getCustomMinecraftManifest().isPresent()) {
|
||||
ManifestVersion.Versions customVersion = new ManifestVersion.Versions();
|
||||
customVersion.id = minecraftVersion;
|
||||
customVersion.url = getExtension().getCustomMinecraftManifest().get();
|
||||
version = customVersion;
|
||||
getProject().getLogger().lifecycle("Using custom minecraft manifest");
|
||||
}
|
||||
|
||||
if (version == null) {
|
||||
version = mcManifest.versions().stream()
|
||||
.filter(versions -> versions.id.equalsIgnoreCase(minecraftVersion))
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
if (version == null) {
|
||||
version = findExperimentalVersion();
|
||||
}
|
||||
|
||||
if (version == null) {
|
||||
throw new RuntimeException("Failed to find minecraft version: " + minecraftVersion);
|
||||
}
|
||||
|
||||
getProject().getLogger().debug("Downloading Minecraft {} manifest", minecraftVersion);
|
||||
final DownloadBuilder download = getExtension().download(version.url);
|
||||
|
||||
if (version.sha1 != null) {
|
||||
download.sha1(version.sha1);
|
||||
} else {
|
||||
download.defaultCache();
|
||||
}
|
||||
|
||||
download.downloadPath(minecraftJson.toPath());
|
||||
}
|
||||
|
||||
// This attempts to find the version from fabric's own fallback version manifest json.
|
||||
private ManifestVersion.Versions findExperimentalVersion() throws IOException {
|
||||
final String expVersionManifest = getExtension().download(MirrorUtil.getExperimentalVersions(getProject()))
|
||||
.defaultCache()
|
||||
.downloadString(experimentalVersionsJson.toPath());
|
||||
|
||||
final ManifestVersion expManifest = LoomGradlePlugin.OBJECT_MAPPER.readValue(expVersionManifest, ManifestVersion.class);
|
||||
final ManifestVersion.Versions result = expManifest.versions().stream()
|
||||
.filter(versions -> versions.id.equalsIgnoreCase(minecraftVersion))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (result != null) {
|
||||
getProject().getLogger().lifecycle("Using fallback experimental version {}", minecraftVersion);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void downloadJars() throws IOException {
|
||||
try (ProgressGroup progressGroup = new ProgressGroup(getProject(), "Download Minecraft jars");
|
||||
DownloadExecutor executor = new DownloadExecutor(2)) {
|
||||
if (provideClient()) {
|
||||
final MinecraftVersionMeta.Download client = versionInfo.download("client");
|
||||
final MinecraftVersionMeta.Download client = getVersionInfo().download("client");
|
||||
getExtension().download(client.url())
|
||||
.sha1(client.sha1())
|
||||
.progress(new GradleDownloadProgressListener("Minecraft client", progressGroup::createProgressLogger))
|
||||
@@ -198,7 +127,7 @@ public abstract class MinecraftProvider {
|
||||
}
|
||||
|
||||
if (provideServer()) {
|
||||
final MinecraftVersionMeta.Download server = versionInfo.download("server");
|
||||
final MinecraftVersionMeta.Download server = getVersionInfo().download("server");
|
||||
getExtension().download(server.url())
|
||||
.sha1(server.sha1())
|
||||
.progress(new GradleDownloadProgressListener("Minecraft server", progressGroup::createProgressLogger))
|
||||
@@ -261,7 +190,7 @@ public abstract class MinecraftProvider {
|
||||
}
|
||||
|
||||
public MinecraftVersionMeta getVersionInfo() {
|
||||
return versionInfo;
|
||||
return Objects.requireNonNull(metadataProvider, "Metadata provider not setup").getVersionMeta();
|
||||
}
|
||||
|
||||
public String getJarPrefix() {
|
||||
|
||||
@@ -43,7 +43,7 @@ import net.fabricmc.loom.configuration.providers.minecraft.library.processors.Ru
|
||||
import net.fabricmc.loom.util.Platform;
|
||||
|
||||
public class LibraryProcessorManager {
|
||||
private static final List<LibraryProcessorFactory<?>> LIBRARY_PROCESSORS = List.of(
|
||||
public static final List<LibraryProcessorFactory> DEFAULT_LIBRARY_PROCESSORS = List.of(
|
||||
ArmNativesLibraryProcessor::new,
|
||||
LegacyASMLibraryProcessor::new,
|
||||
LoomNativeSupportLibraryProcessor::new,
|
||||
@@ -55,22 +55,25 @@ public class LibraryProcessorManager {
|
||||
|
||||
private final Platform platform;
|
||||
private final RepositoryHandler repositories;
|
||||
private final List<LibraryProcessorFactory> libraryProcessorFactories;
|
||||
private final List<String> enabledProcessors;
|
||||
|
||||
public LibraryProcessorManager(Platform platform, RepositoryHandler repositories, List<String> enabledProcessors) {
|
||||
public LibraryProcessorManager(Platform platform, RepositoryHandler repositories, List<LibraryProcessorFactory> libraryProcessorFactories, List<String> enabledProcessors) {
|
||||
this.platform = platform;
|
||||
this.repositories = repositories;
|
||||
this.libraryProcessorFactories = libraryProcessorFactories;
|
||||
this.enabledProcessors = enabledProcessors;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public LibraryProcessorManager(Platform platform, RepositoryHandler repositories) {
|
||||
this(platform, repositories, Collections.emptyList());
|
||||
this(platform, repositories, DEFAULT_LIBRARY_PROCESSORS, Collections.emptyList());
|
||||
}
|
||||
|
||||
private List<LibraryProcessor> getProcessors(LibraryContext context) {
|
||||
var processors = new ArrayList<LibraryProcessor>();
|
||||
|
||||
for (LibraryProcessorFactory<?> factory : LIBRARY_PROCESSORS) {
|
||||
for (LibraryProcessorFactory factory : libraryProcessorFactories) {
|
||||
final LibraryProcessor processor = factory.apply(platform, context);
|
||||
final LibraryProcessor.ApplicationResult applicationResult = processor.getApplicationResult();
|
||||
|
||||
@@ -122,6 +125,6 @@ public class LibraryProcessorManager {
|
||||
return Collections.unmodifiableList(libraries);
|
||||
}
|
||||
|
||||
public interface LibraryProcessorFactory<T extends LibraryProcessor> extends BiFunction<Platform, LibraryContext, T> {
|
||||
public interface LibraryProcessorFactory extends BiFunction<Platform, LibraryContext, LibraryProcessor> {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,13 +59,13 @@ import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvider> implements MappedMinecraftProvider.ProviderImpl {
|
||||
protected final M minecraftProvider;
|
||||
protected final ConfigContext configContext;
|
||||
private final Project project;
|
||||
protected final LoomGradleExtension extension;
|
||||
|
||||
public AbstractMappedMinecraftProvider(ConfigContext configContext, M minecraftProvider) {
|
||||
this.configContext = configContext;
|
||||
public AbstractMappedMinecraftProvider(Project project, M minecraftProvider) {
|
||||
this.minecraftProvider = minecraftProvider;
|
||||
this.extension = configContext.extension();
|
||||
this.project = project;
|
||||
this.extension = LoomGradleExtension.get(project);
|
||||
}
|
||||
|
||||
public abstract MappingsNamespace getTargetNamespace();
|
||||
@@ -76,13 +76,13 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public void provide(boolean applyDependencies) throws Exception {
|
||||
public List<MinecraftJar> provide(ProvideContext context) throws Exception {
|
||||
final List<RemappedJars> remappedJars = getRemappedJars();
|
||||
assert !remappedJars.isEmpty();
|
||||
|
||||
if (!areOutputsValid(remappedJars) || extension.refreshDeps()) {
|
||||
if (!areOutputsValid(remappedJars) || context.refreshOutputs()) {
|
||||
try {
|
||||
remapInputs(remappedJars);
|
||||
remapInputs(remappedJars, context.configContext());
|
||||
} catch (Throwable t) {
|
||||
cleanOutputs(remappedJars);
|
||||
|
||||
@@ -90,17 +90,25 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
|
||||
}
|
||||
}
|
||||
|
||||
if (applyDependencies) {
|
||||
if (context.applyDependencies()) {
|
||||
final List<String> dependencyTargets = getDependencyTargets();
|
||||
|
||||
if (dependencyTargets.isEmpty()) {
|
||||
return;
|
||||
if (!dependencyTargets.isEmpty()) {
|
||||
MinecraftSourceSets.get(getProject()).applyDependencies(
|
||||
(configuration, name) -> getProject().getDependencies().add(configuration, getDependencyNotation(name)),
|
||||
dependencyTargets
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MinecraftSourceSets.get(getProject()).applyDependencies(
|
||||
(configuration, name) -> getProject().getDependencies().add(configuration, getDependencyNotation(name)),
|
||||
dependencyTargets
|
||||
);
|
||||
return remappedJars.stream()
|
||||
.map(RemappedJars::outputJar)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public record ProvideContext(boolean applyDependencies, boolean refreshOutputs, ConfigContext configContext) {
|
||||
ProvideContext withApplyDependencies(boolean applyDependencies) {
|
||||
return new ProvideContext(applyDependencies, refreshOutputs(), configContext());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,15 +168,15 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
|
||||
return true;
|
||||
}
|
||||
|
||||
private void remapInputs(List<RemappedJars> remappedJars) throws IOException {
|
||||
private void remapInputs(List<RemappedJars> remappedJars, ConfigContext configContext) throws IOException {
|
||||
cleanOutputs(remappedJars);
|
||||
|
||||
for (RemappedJars remappedJar : remappedJars) {
|
||||
remapJar(remappedJar);
|
||||
remapJar(remappedJar, configContext);
|
||||
}
|
||||
}
|
||||
|
||||
private void remapJar(RemappedJars remappedJars) throws IOException {
|
||||
private void remapJar(RemappedJars remappedJars, ConfigContext configContext) throws IOException {
|
||||
final MappingConfiguration mappingConfiguration = extension.getMappingConfiguration();
|
||||
final String fromM = remappedJars.sourceNamespace().toString();
|
||||
final String toM = getTargetNamespace().toString();
|
||||
@@ -229,12 +237,8 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigContext getConfigContext() {
|
||||
return configContext;
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return getConfigContext().project();
|
||||
return project;
|
||||
}
|
||||
|
||||
public M getMinecraftProvider() {
|
||||
|
||||
@@ -27,9 +27,9 @@ package net.fabricmc.loom.configuration.providers.minecraft.mapped;
|
||||
import java.util.List;
|
||||
|
||||
import dev.architectury.tinyremapper.TinyRemapper;
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SingleJarEnvType;
|
||||
@@ -37,8 +37,8 @@ import net.fabricmc.loom.configuration.providers.minecraft.SingleJarMinecraftPro
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvider;
|
||||
|
||||
public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftProvider> extends AbstractMappedMinecraftProvider<M> permits IntermediaryMinecraftProvider.MergedImpl, IntermediaryMinecraftProvider.SingleJarImpl, IntermediaryMinecraftProvider.SplitImpl {
|
||||
public IntermediaryMinecraftProvider(ConfigContext configContext, M minecraftProvider) {
|
||||
super(configContext, minecraftProvider);
|
||||
public IntermediaryMinecraftProvider(Project project, M minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,8 +52,8 @@ public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftPr
|
||||
}
|
||||
|
||||
public static final class MergedImpl extends IntermediaryMinecraftProvider<MergedMinecraftProvider> implements Merged {
|
||||
public MergedImpl(ConfigContext configContext, MergedMinecraftProvider minecraftProvider) {
|
||||
super(configContext, minecraftProvider);
|
||||
public MergedImpl(Project project, MergedMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,8 +65,8 @@ public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftPr
|
||||
}
|
||||
|
||||
public static final class SplitImpl extends IntermediaryMinecraftProvider<SplitMinecraftProvider> implements Split {
|
||||
public SplitImpl(ConfigContext configContext, SplitMinecraftProvider minecraftProvider) {
|
||||
super(configContext, minecraftProvider);
|
||||
public SplitImpl(Project project, SplitMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,17 +86,17 @@ public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftPr
|
||||
public static final class SingleJarImpl extends IntermediaryMinecraftProvider<SingleJarMinecraftProvider> implements SingleJar {
|
||||
private final SingleJarEnvType env;
|
||||
|
||||
private SingleJarImpl(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider, SingleJarEnvType env) {
|
||||
super(configContext, minecraftProvider);
|
||||
private SingleJarImpl(Project project, SingleJarMinecraftProvider minecraftProvider, SingleJarEnvType env) {
|
||||
super(project, minecraftProvider);
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public static SingleJarImpl server(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(configContext, minecraftProvider, SingleJarEnvType.SERVER);
|
||||
public static SingleJarImpl server(Project project, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(project, minecraftProvider, SingleJarEnvType.SERVER);
|
||||
}
|
||||
|
||||
public static SingleJarImpl client(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(configContext, minecraftProvider, SingleJarEnvType.CLIENT);
|
||||
public static SingleJarImpl client(Project project, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(project, minecraftProvider, SingleJarEnvType.CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,9 +27,9 @@ package net.fabricmc.loom.configuration.providers.minecraft.mapped;
|
||||
import java.util.List;
|
||||
|
||||
import dev.architectury.tinyremapper.TinyRemapper;
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SingleJarEnvType;
|
||||
@@ -37,8 +37,8 @@ import net.fabricmc.loom.configuration.providers.minecraft.SingleJarMinecraftPro
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvider;
|
||||
|
||||
public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extends AbstractMappedMinecraftProvider<M> {
|
||||
public NamedMinecraftProvider(ConfigContext configContext, M minecraftProvider) {
|
||||
super(configContext, minecraftProvider);
|
||||
public NamedMinecraftProvider(Project project, M minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,8 +52,8 @@ public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extend
|
||||
}
|
||||
|
||||
public static final class MergedImpl extends NamedMinecraftProvider<MergedMinecraftProvider> implements Merged {
|
||||
public MergedImpl(ConfigContext configContext, MergedMinecraftProvider minecraftProvider) {
|
||||
super(configContext, minecraftProvider);
|
||||
public MergedImpl(Project project, MergedMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,8 +70,8 @@ public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extend
|
||||
}
|
||||
|
||||
public static final class SplitImpl extends NamedMinecraftProvider<SplitMinecraftProvider> implements Split {
|
||||
public SplitImpl(ConfigContext configContext, SplitMinecraftProvider minecraftProvider) {
|
||||
super(configContext, minecraftProvider);
|
||||
public SplitImpl(Project project, SplitMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,17 +96,17 @@ public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extend
|
||||
public static final class SingleJarImpl extends NamedMinecraftProvider<SingleJarMinecraftProvider> implements SingleJar {
|
||||
private final SingleJarEnvType env;
|
||||
|
||||
private SingleJarImpl(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider, SingleJarEnvType env) {
|
||||
super(configContext, minecraftProvider);
|
||||
private SingleJarImpl(Project project, SingleJarMinecraftProvider minecraftProvider, SingleJarEnvType env) {
|
||||
super(project, minecraftProvider);
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public static SingleJarImpl server(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(configContext, minecraftProvider, SingleJarEnvType.SERVER);
|
||||
public static SingleJarImpl server(Project project, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(project, minecraftProvider, SingleJarEnvType.SERVER);
|
||||
}
|
||||
|
||||
public static SingleJarImpl client(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(configContext, minecraftProvider, SingleJarEnvType.CLIENT);
|
||||
public static SingleJarImpl client(Project project, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(project, minecraftProvider, SingleJarEnvType.CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,10 +29,14 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.mods.dependency.LocalMavenHelper;
|
||||
import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.processors.ProcessorContextImpl;
|
||||
@@ -49,26 +53,31 @@ public abstract class ProcessedNamedMinecraftProvider<M extends MinecraftProvide
|
||||
private final MinecraftJarProcessorManager jarProcessorManager;
|
||||
|
||||
public ProcessedNamedMinecraftProvider(P parentMinecraftProvide, MinecraftJarProcessorManager jarProcessorManager) {
|
||||
super(parentMinecraftProvide.getConfigContext(), parentMinecraftProvide.getMinecraftProvider());
|
||||
super(parentMinecraftProvide.getProject(), parentMinecraftProvide.getMinecraftProvider());
|
||||
this.parentMinecraftProvider = parentMinecraftProvide;
|
||||
this.jarProcessorManager = Objects.requireNonNull(jarProcessorManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provide(boolean applyDependencies) throws Exception {
|
||||
parentMinecraftProvider.provide(false);
|
||||
public List<MinecraftJar> provide(ProvideContext context) throws Exception {
|
||||
parentMinecraftProvider.provide(context.withApplyDependencies(false));
|
||||
|
||||
boolean requiresProcessing = parentMinecraftProvider.getMinecraftJars().stream()
|
||||
boolean requiresProcessing = context.refreshOutputs() || parentMinecraftProvider.getMinecraftJars().stream()
|
||||
.map(this::getProcessedPath)
|
||||
.anyMatch(jarProcessorManager::requiresProcessingJar);
|
||||
|
||||
final Map<MinecraftJar, MinecraftJar> minecraftJarOutputMap = parentMinecraftProvider.getMinecraftJars().stream()
|
||||
.collect(Collectors.toMap(Function.identity(), this::getProcessedJar));
|
||||
|
||||
if (requiresProcessing) {
|
||||
processJars();
|
||||
processJars(minecraftJarOutputMap, context.configContext());
|
||||
}
|
||||
|
||||
if (applyDependencies) {
|
||||
if (context.applyDependencies()) {
|
||||
applyDependencies();
|
||||
}
|
||||
|
||||
return List.copyOf(minecraftJarOutputMap.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,14 +85,17 @@ public abstract class ProcessedNamedMinecraftProvider<M extends MinecraftProvide
|
||||
return MavenScope.LOCAL;
|
||||
}
|
||||
|
||||
private void processJars() throws IOException {
|
||||
for (MinecraftJar minecraftJar : parentMinecraftProvider.getMinecraftJars()) {
|
||||
final MinecraftJar outputJar = getProcessedJar(minecraftJar);
|
||||
private void processJars(Map<MinecraftJar, MinecraftJar> minecraftJarMap, ConfigContext configContext) throws IOException {
|
||||
for (Map.Entry<MinecraftJar, MinecraftJar> entry : minecraftJarMap.entrySet()) {
|
||||
final MinecraftJar minecraftJar = entry.getKey();
|
||||
final MinecraftJar outputJar = entry.getValue();
|
||||
deleteSimilarJars(outputJar.getPath());
|
||||
|
||||
final LocalMavenHelper mavenHelper = getMavenHelper(minecraftJar.getName());
|
||||
final Path outputPath = mavenHelper.copyToMaven(minecraftJar.getPath(), null);
|
||||
|
||||
assert outputJar.getPath().equals(outputPath);
|
||||
|
||||
jarProcessorManager.processJar(outputPath, new ProcessorContextImpl(configContext, minecraftJar));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.google.common.base.Suppliers;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.provider.Provider;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
@@ -49,6 +50,7 @@ import net.fabricmc.loom.configuration.providers.forge.ForgeRunsProvider;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.IntermediaryMappingsProvider;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessorManager;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.SrgMinecraftProvider;
|
||||
@@ -76,6 +78,7 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||
private InstallerData installerData;
|
||||
private boolean refreshDeps;
|
||||
private Provider<Boolean> multiProjectOptimisation;
|
||||
private final ListProperty<LibraryProcessorManager.LibraryProcessorFactory> libraryProcessorFactories;
|
||||
|
||||
// +-------------------+
|
||||
// | Architectury Loom |
|
||||
@@ -103,6 +106,9 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||
|
||||
refreshDeps = manualRefreshDeps();
|
||||
multiProjectOptimisation = GradleUtils.getBooleanPropertyProvider(project, Constants.Properties.MULTI_PROJECT_OPTIMISATION);
|
||||
libraryProcessorFactories = project.getObjects().listProperty(LibraryProcessorManager.LibraryProcessorFactory.class);
|
||||
libraryProcessorFactories.addAll(LibraryProcessorManager.DEFAULT_LIBRARY_PROCESSORS);
|
||||
libraryProcessorFactories.finalizeValueOnRead();
|
||||
|
||||
if (refreshDeps) {
|
||||
project.getLogger().lifecycle("Refresh dependencies is in use, loom will be significantly slower.");
|
||||
@@ -262,6 +268,11 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||
return multiProjectOptimisation.getOrElse(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListProperty<LibraryProcessorManager.LibraryProcessorFactory> getLibraryProcessors() {
|
||||
return libraryProcessorFactories;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T extends IntermediateMappingsProvider> void configureIntermediateMappingsProviderInternal(T provider) {
|
||||
provider.getMinecraftVersion().set(getProject().provider(() -> getMinecraftProvider().minecraftVersion()));
|
||||
|
||||
@@ -38,18 +38,25 @@ import java.util.stream.Collectors;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.services.ServiceReference;
|
||||
import org.gradle.api.specs.Spec;
|
||||
import org.gradle.api.tasks.JavaExec;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import net.fabricmc.loom.configuration.ide.RunConfig;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.gradle.SyncTaskBuildService;
|
||||
|
||||
public abstract class AbstractRunTask extends JavaExec {
|
||||
private final RunConfig config;
|
||||
// We control the classpath, as we use a ArgFile to pass it over the command line: https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html#commandlineargfile
|
||||
private final ConfigurableFileCollection classpath = getProject().getObjects().fileCollection();
|
||||
|
||||
// Prevent Gradle from running two run tasks in parallel
|
||||
@ServiceReference(SyncTaskBuildService.NAME)
|
||||
abstract Property<SyncTaskBuildService> getSyncTask();
|
||||
|
||||
public AbstractRunTask(Function<Project, RunConfig> configProvider) {
|
||||
super();
|
||||
setGroup(Constants.TaskGroup.FABRIC);
|
||||
|
||||
@@ -26,6 +26,7 @@ package net.fabricmc.loom.task;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.io.Writer;
|
||||
@@ -49,10 +50,14 @@ import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.services.ServiceReference;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputFile;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
import org.gradle.api.tasks.OutputFile;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.gradle.process.ExecOperations;
|
||||
import org.gradle.process.ExecResult;
|
||||
import org.gradle.work.DisableCachingByDefault;
|
||||
import org.gradle.workers.WorkAction;
|
||||
import org.gradle.workers.WorkParameters;
|
||||
@@ -68,6 +73,8 @@ import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.ConfigContextImpl;
|
||||
import net.fabricmc.loom.configuration.processors.MappingProcessorContextImpl;
|
||||
import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.AbstractMappedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.sources.ForgeSourcesRemapper;
|
||||
import net.fabricmc.loom.decompilers.LineNumberRemapper;
|
||||
import net.fabricmc.loom.decompilers.linemap.LineMapClassFilter;
|
||||
@@ -76,6 +83,7 @@ import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.FileSystemUtil;
|
||||
import net.fabricmc.loom.util.IOStringConsumer;
|
||||
import net.fabricmc.loom.util.Platform;
|
||||
import net.fabricmc.loom.util.gradle.SyncTaskBuildService;
|
||||
import net.fabricmc.loom.util.gradle.ThreadedProgressLoggerConsumer;
|
||||
import net.fabricmc.loom.util.gradle.ThreadedSimpleProgressLogger;
|
||||
import net.fabricmc.loom.util.gradle.WorkerDaemonClientsManagerHelper;
|
||||
@@ -92,16 +100,10 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
private final DecompilerOptions decompilerOptions;
|
||||
|
||||
/**
|
||||
* The jar to decompile, can be the unpick jar.
|
||||
* The jar name to decompile, {@link MinecraftJar#getName()}.
|
||||
*/
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getInputJar();
|
||||
|
||||
/**
|
||||
* The jar used at runtime.
|
||||
*/
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getRuntimeJar();
|
||||
@Input
|
||||
public abstract Property<String> getInputJarName();
|
||||
|
||||
@InputFiles
|
||||
public abstract ConfigurableFileCollection getClasspath();
|
||||
@@ -109,12 +111,33 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
@OutputFile
|
||||
public abstract RegularFileProperty getOutputJar();
|
||||
|
||||
// Unpick
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getUnpickDefinitions();
|
||||
|
||||
@InputFiles
|
||||
public abstract ConfigurableFileCollection getUnpickConstantJar();
|
||||
|
||||
@InputFiles
|
||||
public abstract ConfigurableFileCollection getUnpickClasspath();
|
||||
|
||||
@OutputFile
|
||||
public abstract RegularFileProperty getUnpickOutputJar();
|
||||
|
||||
// Injects
|
||||
@Inject
|
||||
public abstract WorkerExecutor getWorkerExecutor();
|
||||
|
||||
@Inject
|
||||
public abstract ExecOperations getExecOperations();
|
||||
|
||||
@Inject
|
||||
public abstract WorkerDaemonClientsManager getWorkerDaemonClientsManager();
|
||||
|
||||
// Prevent Gradle from running two gen sources tasks in parallel
|
||||
@ServiceReference(SyncTaskBuildService.NAME)
|
||||
abstract Property<SyncTaskBuildService> getSyncTask();
|
||||
|
||||
@Inject
|
||||
public GenerateSourcesTask(DecompilerOptions decompilerOptions) {
|
||||
this.decompilerOptions = decompilerOptions;
|
||||
@@ -122,8 +145,6 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
getOutputs().upToDateWhen((o) -> false);
|
||||
getClasspath().from(decompilerOptions.getClasspath()).finalizeValueOnRead();
|
||||
dependsOn(decompilerOptions.getClasspath().getBuiltBy());
|
||||
|
||||
getOutputJar().fileProvider(getProject().provider(() -> getMappedJarFileWithSuffix("-sources.jar")));
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
@@ -134,10 +155,20 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
throw new UnsupportedOperationException("GenSources task requires a 64bit JVM to run due to the memory requirements.");
|
||||
}
|
||||
|
||||
final MinecraftJar minecraftJar = rebuildInputJar();
|
||||
// Input jar is the jar to decompile, this may be unpicked.
|
||||
Path inputJar = minecraftJar.getPath();
|
||||
// Runtime jar is the jar used to run the game
|
||||
final Path runtimeJar = inputJar;
|
||||
|
||||
if (getUnpickDefinitions().isPresent()) {
|
||||
inputJar = unpickJar(inputJar);
|
||||
}
|
||||
|
||||
if (!platform.supportsUnixDomainSockets()) {
|
||||
getProject().getLogger().warn("Decompile worker logging disabled as Unix Domain Sockets is not supported on your operating system.");
|
||||
|
||||
doWork(null);
|
||||
doWork(null, inputJar, runtimeJar);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -147,7 +178,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
|
||||
try (ThreadedProgressLoggerConsumer loggerConsumer = new ThreadedProgressLoggerConsumer(getProject(), decompilerOptions.getName(), "Decompiling minecraft sources");
|
||||
IPCServer logReceiver = new IPCServer(ipcPath, loggerConsumer)) {
|
||||
doWork(logReceiver);
|
||||
doWork(logReceiver, inputJar, runtimeJar);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("Failed to shutdown log receiver", e);
|
||||
} finally {
|
||||
@@ -162,18 +193,94 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
}
|
||||
}
|
||||
|
||||
private void doWork(@Nullable IPCServer ipcServer) {
|
||||
// Re-run the named minecraft provider to give us a fresh jar to decompile.
|
||||
// This prevents re-applying line maps on an existing jar.
|
||||
private MinecraftJar rebuildInputJar() {
|
||||
final List<MinecraftJar> minecraftJars;
|
||||
|
||||
try (var serviceManager = new ScopedSharedServiceManager()) {
|
||||
final var configContext = new ConfigContextImpl(getProject(), serviceManager, getExtension());
|
||||
final var provideContext = new AbstractMappedMinecraftProvider.ProvideContext(false, true, configContext);
|
||||
minecraftJars = getExtension().getNamedMinecraftProvider().provide(provideContext);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to rebuild input jars", e);
|
||||
}
|
||||
|
||||
for (MinecraftJar minecraftJar : minecraftJars) {
|
||||
if (minecraftJar.getName().equals(getInputJarName().get())) {
|
||||
return minecraftJar;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Could not find minecraft jar (%s) but got (%s)".formatted(
|
||||
getInputJarName().get(),
|
||||
minecraftJars.stream().map(MinecraftJar::getName).collect(Collectors.joining(", ")))
|
||||
);
|
||||
}
|
||||
|
||||
private Path unpickJar(Path inputJar) {
|
||||
final Path outputJar = getUnpickOutputJar().get().getAsFile().toPath();
|
||||
final List<String> args = getUnpickArgs(inputJar, outputJar);
|
||||
|
||||
ExecResult result = getExecOperations().javaexec(spec -> {
|
||||
spec.getMainClass().set("daomephsta.unpick.cli.Main");
|
||||
spec.classpath(getProject().getConfigurations().getByName(Constants.Configurations.UNPICK_CLASSPATH));
|
||||
spec.args(args);
|
||||
spec.systemProperty("java.util.logging.config.file", writeUnpickLogConfig().getAbsolutePath());
|
||||
});
|
||||
|
||||
result.rethrowFailure();
|
||||
|
||||
return outputJar;
|
||||
}
|
||||
|
||||
private List<String> getUnpickArgs(Path inputJar, Path outputJar) {
|
||||
var fileArgs = new ArrayList<File>();
|
||||
|
||||
fileArgs.add(inputJar.toFile());
|
||||
fileArgs.add(outputJar.toFile());
|
||||
fileArgs.add(getUnpickDefinitions().get().getAsFile());
|
||||
fileArgs.add(getUnpickConstantJar().getSingleFile());
|
||||
|
||||
// Classpath
|
||||
for (Path minecraftJar : getExtension().getMinecraftJars(MappingsNamespace.NAMED)) {
|
||||
fileArgs.add(minecraftJar.toFile());
|
||||
}
|
||||
|
||||
for (File file : getUnpickClasspath()) {
|
||||
fileArgs.add(file);
|
||||
}
|
||||
|
||||
return fileArgs.stream()
|
||||
.map(File::getAbsolutePath)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private File writeUnpickLogConfig() {
|
||||
final File unpickLoggingConfigFile = getExtension().getFiles().getUnpickLoggingConfigFile();
|
||||
|
||||
try (InputStream is = GenerateSourcesTask.class.getClassLoader().getResourceAsStream("unpick-logging.properties")) {
|
||||
Files.deleteIfExists(unpickLoggingConfigFile.toPath());
|
||||
Files.copy(Objects.requireNonNull(is), unpickLoggingConfigFile.toPath());
|
||||
} catch (IOException e) {
|
||||
throw new org.gradle.api.UncheckedIOException("Failed to copy unpick logging config", e);
|
||||
}
|
||||
|
||||
return unpickLoggingConfigFile;
|
||||
}
|
||||
|
||||
private void doWork(@Nullable IPCServer ipcServer, Path inputJar, Path runtimeJar) {
|
||||
final String jvmMarkerValue = UUID.randomUUID().toString();
|
||||
final WorkQueue workQueue = createWorkQueue(jvmMarkerValue);
|
||||
|
||||
workQueue.submit(DecompileAction.class, params -> {
|
||||
params.getDecompilerOptions().set(decompilerOptions.toDto());
|
||||
|
||||
params.getInputJar().set(getInputJar());
|
||||
params.getRuntimeJar().set(getRuntimeJar());
|
||||
params.getInputJar().set(inputJar.toFile());
|
||||
params.getRuntimeJar().set(runtimeJar.toFile());
|
||||
params.getSourcesDestinationJar().set(getOutputJar());
|
||||
params.getLinemap().set(getMappedJarFileWithSuffix("-sources.lmap"));
|
||||
params.getLinemapJar().set(getMappedJarFileWithSuffix("-linemapped.jar"));
|
||||
params.getLinemap().set(getMappedJarFileWithSuffix("-sources.lmap", runtimeJar));
|
||||
params.getLinemapJar().set(getMappedJarFileWithSuffix("-linemapped.jar", runtimeJar));
|
||||
params.getMappings().set(getMappings().toFile());
|
||||
|
||||
if (ipcServer != null) {
|
||||
@@ -342,16 +449,12 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
}
|
||||
}
|
||||
|
||||
private File getMappedJarFileWithSuffix(String suffix) {
|
||||
return getMappedJarFileWithSuffix(getRuntimeJar(), suffix);
|
||||
}
|
||||
|
||||
static File getMappedJarFileWithSuffix(RegularFileProperty runtimeJar, String suffix) {
|
||||
return getMappedJarFileWithSuffix(runtimeJar.get().getAsFile(), suffix);
|
||||
return getMappedJarFileWithSuffix(suffix, runtimeJar.get().getAsFile().toPath());
|
||||
}
|
||||
|
||||
public static File getMappedJarFileWithSuffix(File runtimeJar, String suffix) {
|
||||
String path = runtimeJar.getAbsolutePath();
|
||||
public static File getMappedJarFileWithSuffix(String suffix, Path runtimeJar) {
|
||||
final String path = runtimeJar.toFile().getAbsolutePath();
|
||||
|
||||
if (!path.toLowerCase(Locale.ROOT).endsWith(".jar")) {
|
||||
throw new RuntimeException("Invalid mapped JAR path: " + path);
|
||||
|
||||
@@ -165,6 +165,10 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
if (getLoomExtension().multiProjectOptimisation()) {
|
||||
setupPreparationTask();
|
||||
}
|
||||
|
||||
// Make outputs reproducible by default
|
||||
setReproducibleFileOrder(true);
|
||||
setPreserveFileTimestamps(false);
|
||||
}
|
||||
|
||||
private void setupPreparationTask() {
|
||||
|
||||
@@ -48,6 +48,7 @@ import net.fabricmc.loom.util.PropertyUtil;
|
||||
import net.fabricmc.loom.util.aw2at.Aw2At;
|
||||
import net.fabricmc.loom.util.gradle.GradleUtils;
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||
import net.fabricmc.loom.util.gradle.SyncTaskBuildService;
|
||||
|
||||
public abstract class RemapTaskConfiguration implements Runnable {
|
||||
public static final String REMAP_JAR_TASK_NAME = "remapJar";
|
||||
@@ -68,6 +69,8 @@ public abstract class RemapTaskConfiguration implements Runnable {
|
||||
public void run() {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
||||
|
||||
SyncTaskBuildService.register(getProject());
|
||||
|
||||
if (GradleUtils.getBooleanProperty(getProject(), Constants.Properties.DONT_REMAP)) {
|
||||
extension.getUnmappedModCollection().from(getTasks().getByName(JavaPlugin.JAR_TASK_NAME));
|
||||
return;
|
||||
|
||||
@@ -29,7 +29,7 @@ import javax.inject.Inject;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfig;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
|
||||
public class RunGameTask extends AbstractRunTask {
|
||||
public abstract class RunGameTask extends AbstractRunTask {
|
||||
@Inject
|
||||
public RunGameTask(RunConfigSettings settings) {
|
||||
super(proj -> RunConfig.runConfig(proj, settings));
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 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.task;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.tasks.InputFile;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
import org.gradle.api.tasks.Internal;
|
||||
import org.gradle.api.tasks.JavaExec;
|
||||
import org.gradle.api.tasks.OutputFile;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.extension.LoomFiles;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public abstract class UnpickJarTask extends JavaExec {
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getInputJar();
|
||||
|
||||
@InputFile
|
||||
public abstract RegularFileProperty getUnpickDefinitions();
|
||||
|
||||
@InputFiles
|
||||
// Only 1 file, but it comes from a configuration
|
||||
public abstract ConfigurableFileCollection getConstantJar();
|
||||
|
||||
@InputFiles
|
||||
public abstract ConfigurableFileCollection getUnpickClasspath();
|
||||
|
||||
@OutputFile
|
||||
public abstract RegularFileProperty getOutputJar();
|
||||
|
||||
@Inject
|
||||
public UnpickJarTask() {
|
||||
classpath(getProject().getConfigurations().getByName(Constants.Configurations.UNPICK_CLASSPATH));
|
||||
getMainClass().set("daomephsta.unpick.cli.Main");
|
||||
|
||||
getConstantJar().setFrom(getProject().getConfigurations().getByName(Constants.Configurations.MAPPING_CONSTANTS));
|
||||
getUnpickClasspath().setFrom(getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES));
|
||||
getUnpickClasspath().from(getProject().getConfigurations().getByName(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exec() {
|
||||
fileArg(getInputJar().get().getAsFile(), getOutputJar().get().getAsFile(), getUnpickDefinitions().get().getAsFile());
|
||||
fileArg(getConstantJar().getSingleFile());
|
||||
|
||||
// Classpath
|
||||
for (Path minecraftJar : getExtension().getMinecraftJars(MappingsNamespace.NAMED)) {
|
||||
fileArg(minecraftJar.toFile());
|
||||
}
|
||||
|
||||
for (File file : getUnpickClasspath()) {
|
||||
fileArg(file);
|
||||
}
|
||||
|
||||
writeUnpickLogConfig();
|
||||
systemProperty("java.util.logging.config.file", getDirectories().getUnpickLoggingConfigFile().getAbsolutePath());
|
||||
|
||||
super.exec();
|
||||
}
|
||||
|
||||
private void writeUnpickLogConfig() {
|
||||
try (InputStream is = UnpickJarTask.class.getClassLoader().getResourceAsStream("unpick-logging.properties")) {
|
||||
Files.deleteIfExists(getDirectories().getUnpickLoggingConfigFile().toPath());
|
||||
Files.copy(is, getDirectories().getUnpickLoggingConfigFile().toPath());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to copy unpick logging config", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void fileArg(File... files) {
|
||||
for (File file : files) {
|
||||
args(file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
@Internal
|
||||
protected LoomGradleExtension getExtension() {
|
||||
return LoomGradleExtension.get(getProject());
|
||||
}
|
||||
|
||||
private LoomFiles getDirectories() {
|
||||
return getExtension().getFiles();
|
||||
}
|
||||
}
|
||||
@@ -157,6 +157,7 @@ public abstract class GenerateDLIConfigTask extends AbstractLoomTask {
|
||||
final boolean plainConsole = getProject().getGradle().getStartParameter().getConsoleOutput() == ConsoleOutput.Plain;
|
||||
final boolean ansiSupportedIDE = new File(getProject().getRootDir(), ".vscode").exists()
|
||||
|| new File(getProject().getRootDir(), ".idea").exists()
|
||||
|| new File(getProject().getRootDir(), ".project").exists()
|
||||
|| (Arrays.stream(getProject().getRootDir().listFiles()).anyMatch(file -> file.getName().endsWith(".iws")));
|
||||
|
||||
//Enable ansi by default for idea and vscode when gradle is not ran with plain console.
|
||||
|
||||
@@ -45,6 +45,51 @@ public class ZipReprocessorUtil {
|
||||
|
||||
private ZipReprocessorUtil() { }
|
||||
|
||||
private static final String MANIFEST_LOCATION = "META-INF/MANIFEST.MF";
|
||||
private static final String META_INF = "META-INF/";
|
||||
|
||||
// See https://docs.oracle.com/en/java/javase/20/docs/specs/jar/jar.html#signed-jar-file
|
||||
private static boolean isSpecialFile(String zipEntryName) {
|
||||
if (!zipEntryName.startsWith(META_INF)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String[] parts = zipEntryName.split("/");
|
||||
|
||||
if (parts.length != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parts[1].startsWith("SIG-")
|
||||
|| parts[1].endsWith(".SF")
|
||||
|| parts[1].endsWith(".DSA")
|
||||
|| parts[1].endsWith(".RSA")
|
||||
|| parts[1].endsWith(".EC");
|
||||
}
|
||||
|
||||
private static int specialOrdering(String name1, String name2) {
|
||||
if (name1.equals(name2)) {
|
||||
return 0;
|
||||
} else if (name1.equals(MANIFEST_LOCATION)) {
|
||||
return -1;
|
||||
} else if (name2.equals(MANIFEST_LOCATION)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
boolean isName1Special = isSpecialFile(name1);
|
||||
boolean isName2Special = isSpecialFile(name2);
|
||||
|
||||
if (isName1Special && isName2Special) {
|
||||
return name1.compareTo(name2);
|
||||
} else if (isName1Special) {
|
||||
return -1;
|
||||
} else if (isName2Special) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return name1.compareTo(name2);
|
||||
}
|
||||
|
||||
public static void reprocessZip(File file, boolean reproducibleFileOrder, boolean preserveFileTimestamps) throws IOException {
|
||||
if (!reproducibleFileOrder && preserveFileTimestamps) {
|
||||
return;
|
||||
@@ -54,7 +99,7 @@ public class ZipReprocessorUtil {
|
||||
ZipEntry[] entries;
|
||||
|
||||
if (reproducibleFileOrder) {
|
||||
entries = zipFile.stream().sorted(Comparator.comparing(ZipEntry::getName)).toArray(ZipEntry[]::new);
|
||||
entries = zipFile.stream().sorted(Comparator.comparing(ZipEntry::getName, ZipReprocessorUtil::specialOrdering)).toArray(ZipEntry[]::new);
|
||||
} else {
|
||||
entries = zipFile.stream().toArray(ZipEntry[]::new);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2018-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.util.gradle;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.services.BuildService;
|
||||
import org.gradle.api.services.BuildServiceParameters;
|
||||
|
||||
/**
|
||||
* Add the following snippet to task to prevent tasks running asynchronously with any other task with the same build service.
|
||||
*
|
||||
* <pre>{@code
|
||||
* @ServiceReference(SyncTaskBuildService.NAME)
|
||||
* abstract Property<SyncTaskBuildService> getSyncTask();
|
||||
* }</pre>
|
||||
*/
|
||||
public abstract class SyncTaskBuildService implements BuildService<SyncTaskBuildService.Params> {
|
||||
public static final String NAME = "loomSyncTask";
|
||||
|
||||
public static void register(Project project) {
|
||||
project.getGradle().getSharedServices().registerIfAbsent(
|
||||
NAME,
|
||||
SyncTaskBuildService.class,
|
||||
spec -> spec.getMaxParallelUsages().set(1)
|
||||
);
|
||||
}
|
||||
|
||||
public interface Params extends BuildServiceParameters {
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
* Copyright (c) 2022-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
|
||||
@@ -24,15 +24,17 @@
|
||||
|
||||
package net.fabricmc.loom.util.kotlin;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import kotlinx.metadata.jvm.KotlinClassMetadata;
|
||||
import org.gradle.api.Project;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
|
||||
public class KotlinPluginUtils {
|
||||
private static final String KOTLIN_PLUGIN_ID = "org.jetbrains.kotlin.jvm";
|
||||
private static final Pattern VERSION_PATTERN = Pattern.compile("\\((.*?)\\)");
|
||||
private static final Pattern VERSION_PATTERN = Pattern.compile("\\((?<version>.*?)\\)|(?<newVersion>^[^(]*$)");
|
||||
|
||||
public static boolean hasKotlinPlugin(Project project) {
|
||||
return project.getPluginManager().hasPlugin(KOTLIN_PLUGIN_ID);
|
||||
@@ -43,15 +45,27 @@ public class KotlinPluginUtils {
|
||||
/*
|
||||
1.7.0-RC-release-217(1.7.0-RC)
|
||||
1.6.21-release-334(1.6.21)
|
||||
1.9.0-Beta
|
||||
*/
|
||||
final String implVersion = kotlinPluginClass.getPackage().getImplementationVersion();
|
||||
return parseKotlinVersion(implVersion);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static String parseKotlinVersion(String implVersion) {
|
||||
final Matcher matcher = VERSION_PATTERN.matcher(implVersion);
|
||||
|
||||
if (!matcher.find()) {
|
||||
throw new IllegalStateException("Unable to match Kotlin version from: " + implVersion);
|
||||
}
|
||||
|
||||
return matcher.group(1);
|
||||
String version = matcher.group("version");
|
||||
|
||||
if (version == null) {
|
||||
version = matcher.group("newVersion");
|
||||
}
|
||||
|
||||
return Objects.requireNonNull(version);
|
||||
}
|
||||
|
||||
public static String getKotlinMetadataVersion() {
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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.integration
|
||||
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.CompletionStage
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
import com.microsoft.java.debug.core.DebugUtility
|
||||
import com.microsoft.java.debug.core.IDebugSession
|
||||
import com.sun.jdi.Bootstrap
|
||||
import com.sun.jdi.event.BreakpointEvent
|
||||
import groovy.transform.CompileStatic
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.Function
|
||||
import spock.lang.Specification
|
||||
import spock.lang.Timeout
|
||||
|
||||
import net.fabricmc.loom.test.util.GradleProjectTestTrait
|
||||
import net.fabricmc.loom.util.ZipUtils
|
||||
|
||||
import static net.fabricmc.loom.test.LoomTestConstants.PRE_RELEASE_GRADLE
|
||||
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
|
||||
|
||||
@Timeout(value = 30, unit = TimeUnit.MINUTES)
|
||||
class DebugLineNumbersTest extends Specification implements GradleProjectTestTrait {
|
||||
static final String MAPPINGS = "1.20.1-net.fabricmc.yarn.1_20_1.1.20.1+build.1-v2"
|
||||
static final Map<String, Integer> BREAKPOINTS = [
|
||||
"net.minecraft.server.dedicated.ServerPropertiesLoader": 16,
|
||||
"net.minecraft.server.dedicated.MinecraftDedicatedServer": 107,
|
||||
"net.minecraft.registry.RegistryOps": 67
|
||||
]
|
||||
|
||||
def "Debug test"() {
|
||||
setup:
|
||||
def gradle = gradleProject(project: "minimalBase", version: PRE_RELEASE_GRADLE)
|
||||
gradle.buildGradle << '''
|
||||
loom {
|
||||
// Just test with the server, no need to also decompile the client
|
||||
serverOnlyMinecraftJar()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:1.20.1"
|
||||
mappings "net.fabricmc:yarn:1.20.1+build.1:v2"
|
||||
modImplementation 'net.fabricmc:fabric-loader:0.14.21'
|
||||
}
|
||||
|
||||
runServer {
|
||||
debugOptions {
|
||||
enabled = true
|
||||
port = 8050
|
||||
host = "*"
|
||||
server = true
|
||||
suspend = true
|
||||
}
|
||||
}
|
||||
'''
|
||||
when:
|
||||
// First generate sources
|
||||
def genSources = gradle.run(task: "genSources")
|
||||
genSources.task(":genSources").outcome == SUCCESS
|
||||
|
||||
// Print out the source of the file
|
||||
def lines = getClassSource(gradle, "net/minecraft/server/dedicated/ServerPropertiesLoader.java").lines().toList()
|
||||
int l = 1
|
||||
for (final def line in lines) {
|
||||
//println(l++ + ": " + line)
|
||||
}
|
||||
|
||||
// I agree
|
||||
def runDir = new File(gradle.projectDir, "run")
|
||||
runDir.mkdirs()
|
||||
new File(runDir, "eula.txt") << "eula=true"
|
||||
new File(runDir, "server.properties") << ""
|
||||
|
||||
// Run the gradle task off thread
|
||||
def executor = Executors.newSingleThreadExecutor()
|
||||
def resultCF = CompletableFuture.supplyAsync({
|
||||
gradle.run(task: "runServer")
|
||||
}, executor)
|
||||
|
||||
Map<String, CompletableFuture<BreakpointEvent>> futures
|
||||
def debugger = new Debugger(openDebugSession())
|
||||
|
||||
try {
|
||||
futures = BREAKPOINTS.collectEntries { className, line ->
|
||||
[(className): debugger.addBreakpoint(className, line)]
|
||||
}
|
||||
|
||||
// Start running the game, the process has been suspended until this point.
|
||||
debugger.start()
|
||||
|
||||
// Wait for all of the breakpoints
|
||||
futures.values().forEach {
|
||||
def result = it.get()
|
||||
println("Breakpoint triggered: ${result.location()}")
|
||||
}
|
||||
} finally {
|
||||
// Close the debugger and target process
|
||||
debugger.close()
|
||||
}
|
||||
|
||||
def result = resultCF.get()
|
||||
executor.shutdown()
|
||||
|
||||
then:
|
||||
result.task(":runServer").outcome == SUCCESS
|
||||
|
||||
BREAKPOINTS.forEach { className, line ->
|
||||
futures[className].get().location().lineNumber() == line
|
||||
}
|
||||
}
|
||||
|
||||
private static String getClassSource(GradleProject gradle, String classname, String mappings = MAPPINGS) {
|
||||
File sourcesJar = gradle.getGeneratedSources(mappings, "serveronly")
|
||||
return new String(ZipUtils.unpack(sourcesJar.toPath(), classname), StandardCharsets.UTF_8)
|
||||
}
|
||||
|
||||
private static IDebugSession openDebugSession() {
|
||||
int timeout = 5
|
||||
int maxTimeout = 120 / timeout
|
||||
|
||||
for (i in 0..maxTimeout) {
|
||||
try {
|
||||
return DebugUtility.attach(
|
||||
Bootstrap.virtualMachineManager(),
|
||||
"127.0.0.1",
|
||||
8050,
|
||||
timeout
|
||||
)
|
||||
} catch (ConnectException e) {
|
||||
Thread.sleep(timeout * 1000)
|
||||
if (i == maxTimeout) {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException()
|
||||
}
|
||||
|
||||
@CompileStatic // Makes RxJava somewhat usable in Groovy
|
||||
class Debugger implements AutoCloseable {
|
||||
final IDebugSession debugSession
|
||||
|
||||
Debugger(IDebugSession debugSession) {
|
||||
this.debugSession = debugSession
|
||||
|
||||
debugSession.eventHub.events().subscribe({ }) {
|
||||
// Manually bail out, as it seems this can be called after close()
|
||||
it.printStackTrace()
|
||||
System.exit(-1)
|
||||
}
|
||||
}
|
||||
|
||||
CompletableFuture<BreakpointEvent> addBreakpoint(String className, int lineNumber) {
|
||||
def breakpoint = debugSession.createBreakpoint(
|
||||
className,
|
||||
lineNumber,
|
||||
0,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
// Wait for the breakpoint to be installed
|
||||
return breakpoint.install().thenCompose {
|
||||
// Then compose with the first result
|
||||
return breakpointEvents()
|
||||
.filter { event ->
|
||||
event.location().sourcePath().replaceAll("[\\\\/]", ".") == className + ".java" &&
|
||||
event.location().lineNumber() == lineNumber
|
||||
}
|
||||
.firstElement()
|
||||
.to(toCompletionStage())
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> Function<Maybe<T>, CompletionStage<T>> toCompletionStage() {
|
||||
return { Maybe<T> m ->
|
||||
CompletableFuture<T> cf = new CompletableFuture<>()
|
||||
m.subscribe(cf.&complete, cf.&completeExceptionally) { cf.complete(null) }
|
||||
return cf
|
||||
}
|
||||
}
|
||||
|
||||
Observable<BreakpointEvent> breakpointEvents() {
|
||||
return debugSession.getEventHub().breakpointEvents()
|
||||
.map {
|
||||
it.shouldResume = true
|
||||
it.event as BreakpointEvent
|
||||
}
|
||||
}
|
||||
|
||||
void start() {
|
||||
debugSession.start()
|
||||
}
|
||||
|
||||
@Override
|
||||
void close() throws Exception {
|
||||
debugSession.terminate()
|
||||
debugSession.eventHub.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,13 +55,13 @@ class ReproducibleBuildTest extends Specification implements GradleProjectTestTr
|
||||
|
||||
where:
|
||||
version | modHash | sourceHash
|
||||
DEFAULT_GRADLE | "ed3306ef60f434c55048cba8de5dab95" | [
|
||||
"0d9eec9248d93eb6ec4a1cd4d927e609",
|
||||
"436bf54ef015576b0a338d55d9a0bb82"
|
||||
DEFAULT_GRADLE | "174c9b52f4bc6d489548d11b42e853cf" | [
|
||||
"5e6e56df303b4fbaaef372d6f143dbfc",
|
||||
"92b6fbffd0bd14bf3c626750eb86c264"
|
||||
]
|
||||
PRE_RELEASE_GRADLE | "ed3306ef60f434c55048cba8de5dab95" | [
|
||||
"0d9eec9248d93eb6ec4a1cd4d927e609",
|
||||
"436bf54ef015576b0a338d55d9a0bb82"
|
||||
PRE_RELEASE_GRADLE | "174c9b52f4bc6d489548d11b42e853cf" | [
|
||||
"5e6e56df303b4fbaaef372d6f143dbfc",
|
||||
"92b6fbffd0bd14bf3c626750eb86c264"
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ class DownloadFileTest extends DownloadTest {
|
||||
|
||||
def "Progress: String"() {
|
||||
setup:
|
||||
server.get("/progressString") {
|
||||
server.get("/progressFile") {
|
||||
it.result("Hello World")
|
||||
}
|
||||
|
||||
|
||||
@@ -25,17 +25,14 @@
|
||||
package net.fabricmc.loom.test.unit.download
|
||||
|
||||
import io.javalin.Javalin
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Specification
|
||||
|
||||
abstract class DownloadTest extends Specification {
|
||||
static final String PATH = "http://127.0.0.1:9081"
|
||||
|
||||
@Shared
|
||||
Javalin server = Javalin.create { config ->
|
||||
}.start(9081)
|
||||
Javalin server = Javalin.create().start(9081)
|
||||
|
||||
def cleanupSpec() {
|
||||
def cleanup() {
|
||||
server.stop()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.kotlin
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
import net.fabricmc.loom.util.kotlin.KotlinPluginUtils
|
||||
|
||||
class KotlinPluginUtilsTest extends Specification {
|
||||
def "parseKotlinVersion"() {
|
||||
when:
|
||||
def parsedVersion = KotlinPluginUtils.parseKotlinVersion(version)
|
||||
|
||||
then:
|
||||
parsedVersion == expected
|
||||
|
||||
where:
|
||||
version | expected
|
||||
"1.7.0-RC-release-217(1.7.0-RC)" | "1.7.0-RC"
|
||||
"1.6.21-release-334(1.6.21)" | "1.6.21"
|
||||
"1.9.0-Beta" | "1.9.0-Beta"
|
||||
}
|
||||
}
|
||||
@@ -82,7 +82,7 @@ class LibraryProcessorManagerTest extends LibraryProcessorTest {
|
||||
when:
|
||||
def platform = PlatformTestUtils.WINDOWS_X64
|
||||
def (original, context) = getLibs("1.19.2", platform)
|
||||
def processed = new LibraryProcessorManager(platform, GradleTestUtil.mockRepositoryHandler(), [
|
||||
def processed = new LibraryProcessorManager(platform, GradleTestUtil.mockRepositoryHandler(), LibraryProcessorManager.DEFAULT_LIBRARY_PROCESSORS, [
|
||||
RuntimeLog4jLibraryProcessor.class.simpleName
|
||||
]).processLibraries(original, context)
|
||||
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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.providers
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
|
||||
import org.intellij.lang.annotations.Language
|
||||
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMetadataProvider
|
||||
import net.fabricmc.loom.test.LoomTestConstants
|
||||
import net.fabricmc.loom.test.unit.download.DownloadTest
|
||||
import net.fabricmc.loom.util.download.Download
|
||||
|
||||
class MinecraftMetadataProviderTest extends DownloadTest {
|
||||
Path testDir
|
||||
|
||||
def setup() {
|
||||
testDir = LoomTestConstants.TEST_DIR.toPath().resolve("MinecraftMetadataProviderTest")
|
||||
|
||||
testDir.toFile().deleteDir()
|
||||
Files.createDirectories(testDir)
|
||||
}
|
||||
|
||||
def "Cached result"() {
|
||||
setup:
|
||||
int calls = 0
|
||||
server.get("/versionManifest") {
|
||||
it.result(VERSION_MANIFEST_1)
|
||||
calls++
|
||||
}
|
||||
|
||||
when:
|
||||
// Test the builtin caching of the metadata provider
|
||||
def metaProvider = provider("1.20.1")
|
||||
metaProvider.getVersionMeta()
|
||||
def meta = metaProvider.getVersionMeta()
|
||||
|
||||
// Create a new provider to test download caching
|
||||
def meta2 = provider("1.20.1").getVersionMeta()
|
||||
|
||||
then:
|
||||
meta.id() == "1.20.1"
|
||||
meta2.id() == "1.20.1"
|
||||
calls == 1
|
||||
}
|
||||
|
||||
// Tests a fix to https://github.com/FabricMC/fabric-loom/issues/886
|
||||
def "Force download with new version"() {
|
||||
setup:
|
||||
int calls = 0
|
||||
server.get("/versionManifest") {
|
||||
it.result(calls == 0 ? VERSION_MANIFEST_1 : VERSION_MANIFEST_2)
|
||||
calls++
|
||||
}
|
||||
server.get("/experimentalVersionManifest") {
|
||||
it.result(EXP_VERSION_MANIFEST)
|
||||
calls++
|
||||
}
|
||||
|
||||
when:
|
||||
def meta = provider("1.20.1").getVersionMeta()
|
||||
def meta2 = provider("1.20.1-rc1").getVersionMeta()
|
||||
|
||||
then:
|
||||
meta.id() == "1.20.1"
|
||||
meta2.id() == "1.20.1-rc1"
|
||||
calls == 3
|
||||
}
|
||||
|
||||
def "Experimental"() {
|
||||
setup:
|
||||
int calls = 0
|
||||
server.get("/versionManifest") {
|
||||
it.result(VERSION_MANIFEST_1)
|
||||
calls++
|
||||
}
|
||||
server.get("/experimentalVersionManifest") {
|
||||
it.result(EXP_VERSION_MANIFEST)
|
||||
calls++
|
||||
}
|
||||
|
||||
when:
|
||||
def meta = provider("1.19_deep_dark_experimental_snapshot-1").getVersionMeta()
|
||||
|
||||
then:
|
||||
meta.id() == "1.19_deep_dark_experimental_snapshot-1"
|
||||
calls == 2
|
||||
}
|
||||
|
||||
def "Custom manifest"() {
|
||||
setup:
|
||||
server.get("/customManifest") {
|
||||
it.result('{"id": "2.0.0"}')
|
||||
}
|
||||
|
||||
when:
|
||||
def meta = provider("2.0.0", "$PATH/customManifest").getVersionMeta()
|
||||
|
||||
then:
|
||||
meta.id() == "2.0.0"
|
||||
}
|
||||
|
||||
def "Get unknown"() {
|
||||
setup:
|
||||
int calls = 0
|
||||
server.get("/versionManifest") {
|
||||
it.result(VERSION_MANIFEST_1)
|
||||
calls++
|
||||
}
|
||||
server.get("/experimentalVersionManifest") {
|
||||
it.result(EXP_VERSION_MANIFEST)
|
||||
calls++
|
||||
}
|
||||
|
||||
when:
|
||||
provider("2.0.0").getVersionMeta()
|
||||
|
||||
then:
|
||||
def e = thrown(RuntimeException)
|
||||
e.message == "Failed to find minecraft version: 2.0.0"
|
||||
calls == 4
|
||||
}
|
||||
|
||||
private MinecraftMetadataProvider provider(String version, String customUrl = null) {
|
||||
return new MinecraftMetadataProvider(
|
||||
options(version, customUrl),
|
||||
Download.&create
|
||||
)
|
||||
}
|
||||
|
||||
private MinecraftMetadataProvider.Options options(String version, String customUrl) {
|
||||
return new MinecraftMetadataProvider.Options(
|
||||
version,
|
||||
"$PATH/versionManifest",
|
||||
"$PATH/experimentalVersionManifest",
|
||||
customUrl,
|
||||
testDir.resolve("version_manifest.json"),
|
||||
testDir.resolve("experimental_version_manifest.json"),
|
||||
testDir.resolve("${version}.json")
|
||||
)
|
||||
}
|
||||
|
||||
@Language("json")
|
||||
private static final String VERSION_MANIFEST_1 = """
|
||||
{
|
||||
"latest": {
|
||||
"release": "1.20.1",
|
||||
"snapshot": "1.20.1"
|
||||
},
|
||||
"versions": [
|
||||
{
|
||||
"id": "1.20.1",
|
||||
"url": "https://piston-meta.mojang.com/v1/packages/715ccf3330885e75b205124f09f8712542cbe7e0/1.20.1.json",
|
||||
"sha1": "715ccf3330885e75b205124f09f8712542cbe7e0"
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
|
||||
@Language("json")
|
||||
private static final String VERSION_MANIFEST_2 = """
|
||||
{
|
||||
"latest": {
|
||||
"release": "1.20.1",
|
||||
"snapshot": "1.20.1"
|
||||
},
|
||||
"versions": [
|
||||
{
|
||||
"id": "1.20.1",
|
||||
"url": "https://piston-meta.mojang.com/v1/packages/715ccf3330885e75b205124f09f8712542cbe7e0/1.20.1.json",
|
||||
"sha1": "715ccf3330885e75b205124f09f8712542cbe7e0"
|
||||
},
|
||||
{
|
||||
"id": "1.20.1-rc1",
|
||||
"url": "https://piston-meta.mojang.com/v1/packages/61c85d1e228b4ca6e48d2da903d2399c12b6a880/1.20.1-rc1.json",
|
||||
"sha1": "61c85d1e228b4ca6e48d2da903d2399c12b6a880"
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
@Language("json")
|
||||
private static final String EXP_VERSION_MANIFEST = """
|
||||
{
|
||||
"latest": {
|
||||
"release": "1.19_deep_dark_experimental_snapshot-1",
|
||||
"snapshot": "1.19_deep_dark_experimental_snapshot-1"
|
||||
},
|
||||
"versions": [
|
||||
{
|
||||
"id": "1.19_deep_dark_experimental_snapshot-1",
|
||||
"url": "https://maven.fabricmc.net/net/minecraft/1_19_deep_dark_experimental_snapshot-1.json",
|
||||
"sha1": "c5b59acb75db612cf446b4ed4bd59b01e10092d1"
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
}
|
||||
@@ -236,8 +236,8 @@ trait GradleProjectTestTrait {
|
||||
return ZipUtils.unpackNullable(file.toPath(), entryName) != null
|
||||
}
|
||||
|
||||
File getGeneratedSources(String mappings) {
|
||||
return new File(getGradleHomeDir(), "caches/fabric-loom/minecraftMaven/net/minecraft/minecraft-merged/${mappings}/minecraft-merged-${mappings}-sources.jar")
|
||||
File getGeneratedSources(String mappings, String jarType = "merged") {
|
||||
return new File(getGradleHomeDir(), "caches/fabric-loom/minecraftMaven/net/minecraft/minecraft-${jarType}/${mappings}/minecraft-${jarType}-${mappings}-sources.jar")
|
||||
}
|
||||
|
||||
File getGeneratedLocalSources(String mappings) {
|
||||
|
||||
@@ -52,12 +52,6 @@ jar {
|
||||
}
|
||||
}
|
||||
|
||||
// Make Jars Reproducible
|
||||
tasks.withType(AbstractArchiveTask) {
|
||||
preserveFileTimestamps = false
|
||||
reproducibleFileOrder = true
|
||||
}
|
||||
|
||||
remapSourcesJar {
|
||||
preserveFileTimestamps = false
|
||||
reproducibleFileOrder = true
|
||||
|
||||
Reference in New Issue
Block a user