diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1ce19c5b..f0613107 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] kotlin = "1.9.24" -asm = "9.6" +asm = "9.7.1" commons-io = "2.15.1" gson = "2.10.1" guava = "33.0.0-jre" diff --git a/gradle/test.libs.versions.toml b/gradle/test.libs.versions.toml index c3c92e8b..2b091d91 100644 --- a/gradle/test.libs.versions.toml +++ b/gradle/test.libs.versions.toml @@ -6,7 +6,7 @@ mockito = "5.13.0" java-debug = "0.52.0" mixin = "0.15.3+mixin.0.8.7" -gradle-nightly = "8.11-20240926001708+0000" +gradle-nightly = "8.12-20241009055624+0000" fabric-loader = "0.16.5" fabric-installer = "1.0.1" diff --git a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java index c53f5c74..0344bbcf 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java @@ -50,6 +50,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.LayeredMappingsFactory; import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration; +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMetadataProvider; 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; @@ -80,6 +81,10 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { LoomDependencyManager getDependencyManager(); + MinecraftMetadataProvider getMetadataProvider(); + + void setMetadataProvider(MinecraftMetadataProvider metadataProvider); + MinecraftProvider getMinecraftProvider(); void setMinecraftProvider(MinecraftProvider minecraftProvider); diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index c9e3fcfe..af61526f 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -74,7 +74,6 @@ import net.fabricmc.loom.configuration.providers.forge.mcpconfig.McpConfigProvid import net.fabricmc.loom.configuration.providers.forge.minecraft.ForgeMinecraftProvider; import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory; import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration; -import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMetadataProvider; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets; @@ -86,7 +85,6 @@ import net.fabricmc.loom.configuration.providers.minecraft.mapped.SrgMinecraftPr import net.fabricmc.loom.configuration.sources.ForgeSourcesRemapper; import net.fabricmc.loom.extension.MixinExtension; import net.fabricmc.loom.util.Checksum; -import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.ExceptionUtil; import net.fabricmc.loom.util.ProcessUtil; import net.fabricmc.loom.util.gradle.GradleUtils; @@ -198,13 +196,10 @@ public abstract class CompileConfiguration implements Runnable { final LoomGradleExtension extension = configContext.extension(); final MinecraftMetadataProvider metadataProvider = MinecraftMetadataProvider.create(configContext); + extension.setMetadataProvider(metadataProvider); var jarConfiguration = extension.getMinecraftJarConfiguration().get(); - if (jarConfiguration == MinecraftJarConfiguration.MERGED && !metadataProvider.getVersionMeta().isVersionOrNewer(Constants.RELEASE_TIME_1_3)) { - jarConfiguration = MinecraftJarConfiguration.LEGACY_MERGED; - } - // Provide the vanilla mc jars final MinecraftProvider minecraftProvider = jarConfiguration.createMinecraftProvider(metadataProvider, configContext); diff --git a/src/main/java/net/fabricmc/loom/configuration/decompile/SplitDecompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/decompile/SplitDecompileConfiguration.java index e47f7ddc..9735fdb7 100644 --- a/src/main/java/net/fabricmc/loom/configuration/decompile/SplitDecompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/decompile/SplitDecompileConfiguration.java @@ -79,12 +79,19 @@ public final class SplitDecompileConfiguration extends DecompileConfiguration { + task.mustRunAfter(commonTask); + }); + project.getTasks().register("genSourcesWith" + decompilerName, task -> { task.setDescription("Decompile minecraft using %s.".formatted(decompilerName)); task.setGroup(Constants.TaskGroup.FABRIC); - task.dependsOn(project.getTasks().named("gen%sSourcesWith%s".formatted("Common", decompilerName))); - task.dependsOn(project.getTasks().named("gen%sSourcesWith%s".formatted("ClientOnly", decompilerName))); + task.dependsOn(commonTask); + task.dependsOn(clientOnlyTask); }); } diff --git a/src/main/java/net/fabricmc/loom/configuration/ide/idea/IdeaSyncTask.java b/src/main/java/net/fabricmc/loom/configuration/ide/idea/IdeaSyncTask.java index d7eb67bd..4fae7e3b 100644 --- a/src/main/java/net/fabricmc/loom/configuration/ide/idea/IdeaSyncTask.java +++ b/src/main/java/net/fabricmc/loom/configuration/ide/idea/IdeaSyncTask.java @@ -109,6 +109,7 @@ public abstract class IdeaSyncTask extends AbstractLoomTask { irc.getRunConfigXml().set(runConfigXml); irc.getExcludedLibraryPaths().set(excludedLibraryPaths); irc.getLaunchFile().set(runConfigFile); + configs.add(irc); } return configs; diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/MinecraftJarProcessorManager.java b/src/main/java/net/fabricmc/loom/configuration/processors/MinecraftJarProcessorManager.java index 39b63559..5f8809df 100644 --- a/src/main/java/net/fabricmc/loom/configuration/processors/MinecraftJarProcessorManager.java +++ b/src/main/java/net/fabricmc/loom/configuration/processors/MinecraftJarProcessorManager.java @@ -116,6 +116,10 @@ public final class MinecraftJarProcessorManager { return Checksum.sha1Hex(getCacheValue().getBytes(StandardCharsets.UTF_8)).substring(0, 10); } + public String getSourceMappingsHash() { + return Checksum.sha1Hex(getCacheValue().getBytes(StandardCharsets.UTF_8)); + } + public boolean requiresProcessingJar(Path jar) { Objects.requireNonNull(jar); diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java index 858d498a..6ad537e6 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java @@ -78,8 +78,10 @@ import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuil import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory; import net.fabricmc.loom.configuration.providers.minecraft.ManifestLocations; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration; +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMetadataProvider; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets; import net.fabricmc.loom.task.GenerateSourcesTask; +import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.DeprecationHelper; import net.fabricmc.loom.util.MirrorUtil; import net.fabricmc.loom.util.ModPlatform; @@ -174,7 +176,23 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA this.minecraftJarProcessors.finalizeValueOnRead(); //noinspection unchecked - this.minecraftJarConfiguration = project.getObjects().property((Class>) (Class) MinecraftJarConfiguration.class).convention(MinecraftJarConfiguration.MERGED); + this.minecraftJarConfiguration = project.getObjects().property((Class>) (Class) MinecraftJarConfiguration.class) + .convention(project.provider(() -> { + final LoomGradleExtension extension = LoomGradleExtension.get(project); + final MinecraftMetadataProvider metadataProvider = extension.getMetadataProvider(); + + // if no configuration is selected by the user, attempt to select one + // based on the mc version and which sides are present for it + if (!metadataProvider.getVersionMeta().downloads().containsKey("server")) { + return MinecraftJarConfiguration.CLIENT_ONLY; + } else if (!metadataProvider.getVersionMeta().downloads().containsKey("client")) { + return MinecraftJarConfiguration.SERVER_ONLY; + } else if (metadataProvider.getVersionMeta().isVersionOrNewer(Constants.RELEASE_TIME_1_3)) { + return MinecraftJarConfiguration.MERGED; + } else { + return MinecraftJarConfiguration.LEGACY_MERGED; + } + })); this.minecraftJarConfiguration.finalizeValueOnRead(); this.accessWidener.finalizeValueOnRead(); diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java index 5909171f..db9e548c 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java @@ -56,6 +56,7 @@ import net.fabricmc.loom.configuration.providers.mappings.IntermediaryMappingsPr import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory; import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration; import net.fabricmc.loom.configuration.providers.mappings.NoOpIntermediateMappingsProvider; +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMetadataProvider; 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; @@ -75,6 +76,7 @@ public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl private final List transitiveAccessWideners = new ArrayList<>(); private LoomDependencyManager dependencyManager; + private MinecraftMetadataProvider metadataProvider; private MinecraftProvider minecraftProvider; private MappingConfiguration mappingConfiguration; private NamedMinecraftProvider namedMinecraftProvider; @@ -151,6 +153,16 @@ public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl return Objects.requireNonNull(dependencyManager, "Cannot get LoomDependencyManager before it has been setup"); } + @Override + public MinecraftMetadataProvider getMetadataProvider() { + return Objects.requireNonNull(metadataProvider, "Cannot get MinecraftMetadataProvider before it has been setup"); + } + + @Override + public void setMetadataProvider(MinecraftMetadataProvider metadataProvider) { + this.metadataProvider = metadataProvider; + } + @Override public MinecraftProvider getMinecraftProvider() { return Objects.requireNonNull(minecraftProvider, "Cannot get MinecraftProvider before it has been setup"); diff --git a/src/main/java/net/fabricmc/loom/task/GenVsCodeProjectTask.java b/src/main/java/net/fabricmc/loom/task/GenVsCodeProjectTask.java index 444f7e57..6684e5ce 100644 --- a/src/main/java/net/fabricmc/loom/task/GenVsCodeProjectTask.java +++ b/src/main/java/net/fabricmc/loom/task/GenVsCodeProjectTask.java @@ -73,7 +73,7 @@ public abstract class GenVsCodeProjectTask extends AbstractLoomTask { public GenVsCodeProjectTask() { setGroup(Constants.TaskGroup.IDE); getLaunchConfigurations().set(getProject().provider(this::getConfigurations)); - getLaunchJson().convention(getProject().getRootProject().getLayout().getProjectDirectory().file("vscode/launch.json")); + getLaunchJson().convention(getProject().getRootProject().getLayout().getProjectDirectory().file(".vscode/launch.json")); } private List getConfigurations() { diff --git a/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java index 61f651b4..65bb5234 100644 --- a/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java +++ b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java @@ -254,6 +254,8 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask { } if (!getUseCache().get()) { + getLogger().info("Not using decompile cache."); + try (var timer = new Timer("Decompiled sources")) { runWithoutCache(); } catch (Exception e) { @@ -346,19 +348,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask { final ClassLineNumbers existingLinenumbers = workRequest.lineNumbers(); final ClassLineNumbers lineNumbers = ClassLineNumbers.merge(existingLinenumbers, outputLineNumbers); - if (lineNumbers == null) { - getLogger().info("No line numbers to remap, skipping remapping"); - return; - } - - Path tempJar = Files.createTempFile("loom", "linenumber-remap.jar"); - Files.delete(tempJar); - - try (var timer = new Timer("Remap line numbers")) { - remapLineNumbers(lineNumbers, classesInputJar, tempJar); - } - - Files.move(tempJar, classesOutputJar, StandardCopyOption.REPLACE_EXISTING); + applyLineNumbers(lineNumbers, classesInputJar, classesOutputJar); try (var timer = new Timer("Prune cache")) { decompileCache.prune(); @@ -366,31 +356,36 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask { } private void runWithoutCache() throws IOException { - Path inputJar = getClassesInputJar().getSingleFile().toPath(); - final Path outputJar = getSourcesOutputJar().get().getAsFile().toPath(); + final Path classesInputJar = getClassesInputJar().getSingleFile().toPath(); + final Path sourcesOutputJar = getSourcesOutputJar().get().getAsFile().toPath(); + final Path classesOutputJar = getClassesOutputJar().getSingleFile().toPath(); - // The final output sources jar + Path workClassesJar = classesInputJar; if (getUnpickDefinitions().isPresent()) { try (var timer = new Timer("Unpick")) { - inputJar = unpickJar(inputJar, null); + workClassesJar = unpickJar(workClassesJar, null); } } ClassLineNumbers lineNumbers; try (var timer = new Timer("Decompile")) { - lineNumbers = runDecompileJob(inputJar, outputJar, null); - removeForgeInnerClassSources(sourcesJar); + lineNumbers = runDecompileJob(workClassesJar, sourcesOutputJar, null); + removeForgeInnerClassSources(sourcesOutputJar); lineNumbers = filterForgeLineNumbers(lineNumbers); } - if (Files.notExists(outputJar)) { + if (Files.notExists(sourcesOutputJar)) { throw new RuntimeException("Failed to decompile sources"); } - getLogger().info("Decompiled sources written to {}", outputJar); + getLogger().info("Decompiled sources written to {}", sourcesOutputJar); + applyLineNumbers(lineNumbers, classesInputJar, classesOutputJar); + } + + private void applyLineNumbers(@Nullable ClassLineNumbers lineNumbers, Path classesInputJar, Path classesOutputJar) throws IOException { if (lineNumbers == null) { getLogger().info("No line numbers to remap, skipping remapping"); return; @@ -400,10 +395,10 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask { Files.delete(tempJar); try (var timer = new Timer("Remap line numbers")) { - remapLineNumbers(lineNumbers, inputJar, tempJar); + remapLineNumbers(lineNumbers, classesInputJar, tempJar); } - Files.move(tempJar, outputJar, StandardCopyOption.REPLACE_EXISTING); + Files.move(tempJar, classesOutputJar, StandardCopyOption.REPLACE_EXISTING); } private String getCacheKey() { diff --git a/src/main/java/net/fabricmc/loom/task/service/LorenzMappingService.java b/src/main/java/net/fabricmc/loom/task/service/LorenzMappingService.java index 4bbc2d5f..14de9791 100644 --- a/src/main/java/net/fabricmc/loom/task/service/LorenzMappingService.java +++ b/src/main/java/net/fabricmc/loom/task/service/LorenzMappingService.java @@ -59,9 +59,9 @@ public final class LorenzMappingService extends Service options.getMappings().set( MappingsService.createOptions( project, - mappingConfiguration.getMappingsPath(mappingOption), - to.toString(), + mappingConfiguration.getMappingsPath(mappingOption), from.toString(), + to.toString(), false) )); } diff --git a/src/main/java/net/fabricmc/loom/task/service/SourceMappingsService.java b/src/main/java/net/fabricmc/loom/task/service/SourceMappingsService.java index 9c178dd3..5173169e 100644 --- a/src/main/java/net/fabricmc/loom/task/service/SourceMappingsService.java +++ b/src/main/java/net/fabricmc/loom/task/service/SourceMappingsService.java @@ -31,13 +31,13 @@ import java.io.Writer; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.InputFiles; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; @@ -56,6 +56,7 @@ import net.fabricmc.mappingio.tree.MemoryMappingTree; public class SourceMappingsService extends Service { public static final ServiceType TYPE = new ServiceType<>(Options.class, SourceMappingsService.class); + private static final Logger LOGGER = LoggerFactory.getLogger(SourceMappingsService.class); public interface Options extends Service.Options { @InputFiles @@ -71,64 +72,63 @@ public class SourceMappingsService extends Service mappingsProcessors = new ArrayList<>(); - - MinecraftJarProcessorManager minecraftJarProcessorManager = MinecraftJarProcessorManager.create(project); - - if (minecraftJarProcessorManager != null) { - mappingsProcessors.add(mappings -> { - try (var serviceFactory = new ScopedServiceFactory()) { - final var configContext = new ConfigContextImpl(project, serviceFactory, extension); - return minecraftJarProcessorManager.processMappings(mappings, new MappingProcessorContextImpl(configContext)); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }); - } - - if (mappingsProcessors.isEmpty()) { - return inputMappings; - } - - boolean transformed = false; - - for (GenerateSourcesTask.MappingsProcessor mappingsProcessor : mappingsProcessors) { - if (mappingsProcessor.transform(mappingTree)) { - transformed = true; + GenerateSourcesTask.MappingsProcessor mappingsProcessor = mappings -> { + try (var serviceFactory = new ScopedServiceFactory()) { + final var configContext = new ConfigContextImpl(project, serviceFactory, extension); + return jarProcessor.processMappings(mappings, new MappingProcessorContextImpl(configContext)); + } catch (IOException e) { + throw new UncheckedIOException(e); } - } + }; + + boolean transformed = mappingsProcessor.transform(mappingTree); if (!transformed) { - return inputMappings; - } - - final Path outputMappings; - - try { - outputMappings = Files.createTempFile("loom-transitive-mappings", ".tiny"); - } catch (IOException e) { - throw new RuntimeException("Failed to create temp file", e); + LOGGER.info("No mappings processors transformed the mappings"); } try (Writer writer = Files.newBufferedWriter(outputMappings, StandardCharsets.UTF_8)) { var tiny2Writer = new Tiny2FileWriter(writer, false); mappingTree.accept(new MappingSourceNsSwitch(tiny2Writer, MappingsNamespace.NAMED.toString())); - } catch (IOException e) { - throw new RuntimeException("Failed to write mappings", e); } - - return outputMappings; } public SourceMappingsService(Options options, ServiceFactory serviceFactory) { diff --git a/src/main/java/net/fabricmc/loom/util/ZipUtils.java b/src/main/java/net/fabricmc/loom/util/ZipUtils.java index 6da4520b..1ca5b83a 100644 --- a/src/main/java/net/fabricmc/loom/util/ZipUtils.java +++ b/src/main/java/net/fabricmc/loom/util/ZipUtils.java @@ -211,7 +211,7 @@ public class ZipUtils { } public static int transformJson(Class typeOfT, Path zip, Map> transforms) throws IOException { - return transformMapped(zip, transforms, bytes -> LoomGradlePlugin.GSON.fromJson(new InputStreamReader(new ByteArrayInputStream(bytes)), typeOfT), + return transformMapped(zip, transforms, bytes -> LoomGradlePlugin.GSON.fromJson(new InputStreamReader(new ByteArrayInputStream(bytes), StandardCharsets.UTF_8), typeOfT), s -> LoomGradlePlugin.GSON.toJson(s, typeOfT).getBytes(StandardCharsets.UTF_8)); } diff --git a/src/main/java/net/fabricmc/loom/util/gradle/GradleUtils.java b/src/main/java/net/fabricmc/loom/util/gradle/GradleUtils.java index bcd96d3b..45dfd90c 100644 --- a/src/main/java/net/fabricmc/loom/util/gradle/GradleUtils.java +++ b/src/main/java/net/fabricmc/loom/util/gradle/GradleUtils.java @@ -32,12 +32,17 @@ import org.gradle.api.Project; import org.gradle.api.artifacts.ProjectDependency; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.internal.artifacts.dependencies.DefaultProjectDependency; +import org.gradle.api.internal.catalog.DelegatingProjectDependency; import org.gradle.api.invocation.Gradle; import org.gradle.api.provider.Provider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import net.fabricmc.loom.util.Constants; public final class GradleUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(GradleUtils.class); + private GradleUtils() { } @@ -97,14 +102,29 @@ public final class GradleUtils { // Get the project from the field with reflection to suppress the deprecation warning. // If you hate it find a solution yourself and make a PR, I'm getting a bit tired of chasing Gradle updates public static Project getDependencyProject(ProjectDependency projectDependency) { - try { - final Class clazz = DefaultProjectDependency.class; - final Field dependencyProject = clazz.getDeclaredField("dependencyProject"); - dependencyProject.setAccessible(true); - return (Project) dependencyProject.get(projectDependency); - } catch (NoSuchFieldException | IllegalAccessException ignored) { - // Just fallback and trigger the warning, this will break in Gradle 9 - return projectDependency.getDependencyProject(); + if (projectDependency instanceof DefaultProjectDependency) { + try { + final Class clazz = DefaultProjectDependency.class; + final Field dependencyProject = clazz.getDeclaredField("dependencyProject"); + dependencyProject.setAccessible(true); + return (Project) dependencyProject.get(projectDependency); + } catch (NoSuchFieldException | IllegalAccessException e) { + LOGGER.warn("Failed to reflect DefaultProjectDependency", e); + } + } else if (projectDependency instanceof DelegatingProjectDependency) { + try { + final Class clazz = DelegatingProjectDependency.class; + final Field delgeate = clazz.getDeclaredField("delegate"); + delgeate.setAccessible(true); + return getDependencyProject((ProjectDependency) delgeate.get(projectDependency)); + } catch (NoSuchFieldException | IllegalAccessException e) { + LOGGER.warn("Failed to reflect DelegatingProjectDependency", e); + } } + + // Just fallback and trigger the warning, this will break in Gradle 9 + final Project project = projectDependency.getDependencyProject(); + LOGGER.warn("Loom was unable to suppress the deprecation warning for ProjectDependency#getDependencyProject, if you are on the latest version of Loom please report this issue to the Loom developers and provide the error above, this WILL stop working in a future Gradle version."); + return project; } } diff --git a/src/main/java/net/fabricmc/loom/util/gradle/SourceSetHelper.java b/src/main/java/net/fabricmc/loom/util/gradle/SourceSetHelper.java index 209703d6..a49cac45 100644 --- a/src/main/java/net/fabricmc/loom/util/gradle/SourceSetHelper.java +++ b/src/main/java/net/fabricmc/loom/util/gradle/SourceSetHelper.java @@ -128,6 +128,7 @@ public final class SourceSetHelper { final List classpath = getGradleClasspath(reference, project); classpath.addAll(getIdeaClasspath(reference, project)); + classpath.addAll(getIdeaModuleCompileOutput(reference)); classpath.addAll(getEclipseClasspath(reference, project)); classpath.addAll(getVscodeClasspath(reference, project)); @@ -192,6 +193,25 @@ public final class SourceSetHelper { return Collections.singletonList(outputDir); } + private static List getIdeaModuleCompileOutput(SourceSetReference reference) { + final File dotIdea = new File(reference.project().getRootDir(), ".idea"); + + if (!dotIdea.exists()) { + // Not an intellij project + return Collections.emptyList(); + } + + final String name = reference.sourceSet().getName(); + final File projectDir = reference.project().getProjectDir(); + final File outDir = new File(projectDir, "out"); + final File sourceSetOutDir = new File(outDir, name.equals(SourceSet.MAIN_SOURCE_SET_NAME) ? "production" : name); + + return List.of( + new File(sourceSetOutDir, "classes"), + new File(sourceSetOutDir, "resources") + ); + } + @Nullable private static String evaluateXpath(File file, @Language("xpath") String expression) { final XPath xpath = XPathFactory.newInstance().newXPath(); diff --git a/src/main/java/net/fabricmc/loom/util/gradle/WorkerDaemonClientsManagerHelper.java b/src/main/java/net/fabricmc/loom/util/gradle/WorkerDaemonClientsManagerHelper.java index d51f7920..07d2f037 100644 --- a/src/main/java/net/fabricmc/loom/util/gradle/WorkerDaemonClientsManagerHelper.java +++ b/src/main/java/net/fabricmc/loom/util/gradle/WorkerDaemonClientsManagerHelper.java @@ -32,6 +32,7 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import org.gradle.api.Transformer; +import org.gradle.process.internal.JvmOptions; import org.gradle.workers.internal.DaemonForkOptions; import org.gradle.workers.internal.WorkerDaemonClientsManager; @@ -45,7 +46,7 @@ public class WorkerDaemonClientsManagerHelper { Transformer, List> transformer = workerDaemonClients -> { for (Object /* WorkerDaemonClient */ client : workerDaemonClients) { DaemonForkOptions forkOptions = getForkOptions(client); - Map systemProperties = forkOptions.getJavaForkOptions().getSystemProperties(); + Map systemProperties = getSystemProperties(forkOptions); if (systemProperties == null || !jvmMarkerValue.equals(systemProperties.get(MARKER_PROP))) { // Not the JVM we are looking for @@ -70,6 +71,30 @@ public class WorkerDaemonClientsManagerHelper { return stopped.get(); } + private static Map getSystemProperties(DaemonForkOptions forkOptions) { + try { + Method getJavaForkOptionsMethod = forkOptions.getClass().getDeclaredMethod("getJavaForkOptions"); + getJavaForkOptionsMethod.setAccessible(true); + Object /* JavaForkOptions */ javaForkOptions = getJavaForkOptionsMethod.invoke(forkOptions); + Method getSystemPropertiesMethod = javaForkOptions.getClass().getDeclaredMethod("getSystemProperties"); + getSystemPropertiesMethod.setAccessible(true); + //noinspection unchecked + return (Map) getSystemPropertiesMethod.invoke(javaForkOptions); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + // Gradle 8.11 and below + } + + // Gradle 8.12+ + try { + Method getJvmOptions = forkOptions.getClass().getDeclaredMethod("getJvmOptions"); + getJvmOptions.setAccessible(true); + JvmOptions jvmOptions = (JvmOptions) getJvmOptions.invoke(forkOptions); + return jvmOptions.getMutableSystemProperties(); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException("Failed to daemon system properties", e); + } + } + private static DaemonForkOptions getForkOptions(Object /* WorkerDaemonClient */ client) { try { Method getForkOptionsMethod = client.getClass().getDeclaredMethod("getForkOptions"); diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/SplitProjectTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/SplitProjectTest.groovy index d0b476ca..4c21db61 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/SplitProjectTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/SplitProjectTest.groovy @@ -29,6 +29,7 @@ import spock.lang.Unroll import net.fabricmc.loom.test.util.GradleProjectTestTrait +import static net.fabricmc.loom.test.LoomTestConstants.PRE_RELEASE_GRADLE import static net.fabricmc.loom.test.LoomTestConstants.STANDARD_TEST_VERSIONS import static org.gradle.testkit.runner.TaskOutcome.SUCCESS @@ -48,4 +49,16 @@ class SplitProjectTest extends Specification implements GradleProjectTestTrait { where: version << STANDARD_TEST_VERSIONS } + + @Unroll + def "genSources (gradle #version)"() { + setup: + def gradle = gradleProject(project: "splitSources", version: PRE_RELEASE_GRADLE) + + when: + def result = gradle.run(tasks: ["genSources"]) + + then: + result.task(":genSources").outcome == SUCCESS + } } diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/UnpickTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/UnpickTest.groovy index fa09aee9..40d684cc 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/UnpickTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/UnpickTest.groovy @@ -37,17 +37,27 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class UnpickTest extends Specification implements GradleProjectTestTrait { static final String MAPPINGS = "21w13a-net.fabricmc.yarn.21w13a.21w13a+build.30-v2" - def "unpick decompile"() { + def "unpick decompile #version #useCache"() { setup: def gradle = gradleProject(project: "unpick", version: version) when: - def result = gradle.run(task: "genSources") + def result = gradle.run(tasks: useCache ? [ + "genSourcesWithVineflower", + "--info" + ] : [ + "genSourcesWithVineflower", + "--no-use-cache", + "--info" + ]) then: - result.task(":genSources").outcome == SUCCESS + result.task(":genSourcesWithVineflower").outcome == SUCCESS getClassSource(gradle, "net/minecraft/block/CakeBlock.java").contains("Block.DEFAULT_SET_BLOCK_STATE_FLAG") + result.output.contains(useCache ? "Using decompile cache." : "Not using decompile cache.") + where: version << STANDARD_TEST_VERSIONS + useCache << [true, false] } def "unpick build"() { diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/GradleUtilsTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/GradleUtilsTest.groovy new file mode 100644 index 00000000..20f9c96f --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/unit/GradleUtilsTest.groovy @@ -0,0 +1,59 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2024 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.test.unit + +import org.gradle.api.internal.artifacts.dependencies.DefaultProjectDependency +import org.gradle.api.internal.catalog.DelegatingProjectDependency +import org.gradle.api.internal.project.ProjectInternal +import spock.lang.Specification + +import net.fabricmc.loom.util.gradle.GradleUtils + +class GradleUtilsTest extends Specification { + def "get default project dependency"() { + given: + def project = Mock(ProjectInternal) + def dependency = new DefaultProjectDependency(project, false) + + when: + def result = GradleUtils.getDependencyProject(dependency) + + then: + result == project + } + + def "get delegated project dependency"() { + given: + def project = Mock(ProjectInternal) + def dependency = new DefaultProjectDependency(project, true) + def delegate = new DelegatingProjectDependency(null, dependency) + + when: + def result = GradleUtils.getDependencyProject(delegate) + + then: + result == project + } +}