From 8250b509a41a76d289e4817edb5bfc27045835ec Mon Sep 17 00:00:00 2001 From: modmuss Date: Sat, 3 Feb 2024 23:26:33 +0000 Subject: [PATCH] Prepare for SelfResolvingDependency's removal & Update to Gradle 8.6 (#1038) * Prepare for SelfResolvingDependency's removal Update to Gradle 8.6 * Update docker images * ProjectDependency is also a SRD * Throw if layered mappings are created too late. --- .github/workflows/test-push.yml | 6 +- .../bootstrap/LoomGradlePluginBootstrap.java | 2 +- gradle/libs.versions.toml | 4 +- gradle/test.libs.versions.toml | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../fabricmc/loom/LoomGradleExtension.java | 7 + .../configuration/CompileConfiguration.java | 4 + .../loom/configuration/DependencyInfo.java | 16 +- .../configuration/FileDependencyInfo.java | 20 ++- .../loom/configuration/mods/ArtifactRef.java | 2 +- .../LayeredMappingSpecBuilderImpl.java | 6 + ...dency.java => LayeredMappingsFactory.java} | 141 +++++++----------- .../mappings/utils/DependencyFileSpec.java | 28 +++- .../extension/LoomGradleExtensionApiImpl.java | 19 ++- .../extension/LoomGradleExtensionImpl.java | 19 ++- .../loom/extension/LoomProblemReporter.java | 51 +++++++ .../loom/task/MigrateMappingsTask.java | 16 +- .../gradle/SelfResolvingDependencyUtils.java | 114 ++++++++++++++ .../loom/test/integration/KotlinTest.groovy | 2 +- .../projects/kotlin/build.gradle.kts | 19 ++- 20 files changed, 350 insertions(+), 130 deletions(-) rename src/main/java/net/fabricmc/loom/configuration/providers/mappings/{LayeredMappingsDependency.java => LayeredMappingsFactory.java} (62%) create mode 100644 src/main/java/net/fabricmc/loom/extension/LoomProblemReporter.java create mode 100644 src/main/java/net/fabricmc/loom/util/gradle/SelfResolvingDependencyUtils.java diff --git a/.github/workflows/test-push.yml b/.github/workflows/test-push.yml index 54e2b1b0..1cc59364 100644 --- a/.github/workflows/test-push.yml +++ b/.github/workflows/test-push.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: false matrix: - version: [8.3.0-jdk17] + version: [8.6.0-jdk17] runs-on: ubuntu-22.04 container: image: gradle:${{ matrix.version }} @@ -39,7 +39,7 @@ jobs: runs-on: ubuntu-22.04 container: - image: gradle:8.3.0-jdk17 + image: gradle:8.6.0-jdk17 options: --user root steps: @@ -58,7 +58,7 @@ jobs: strategy: fail-fast: false matrix: - version: [8.3.0-jdk17] + version: [8.6.0-jdk17] test: ${{ fromJson(needs.prepare_test_matrix.outputs.matrix) }} runs-on: ubuntu-22.04 diff --git a/bootstrap/src/main/java/net/fabricmc/loom/bootstrap/LoomGradlePluginBootstrap.java b/bootstrap/src/main/java/net/fabricmc/loom/bootstrap/LoomGradlePluginBootstrap.java index bd420dd0..8fbf513d 100644 --- a/bootstrap/src/main/java/net/fabricmc/loom/bootstrap/LoomGradlePluginBootstrap.java +++ b/bootstrap/src/main/java/net/fabricmc/loom/bootstrap/LoomGradlePluginBootstrap.java @@ -14,7 +14,7 @@ import org.gradle.util.GradleVersion; */ @SuppressWarnings("unused") public class LoomGradlePluginBootstrap implements Plugin { - private static final String MIN_SUPPORTED_GRADLE_VERSION = "8.3"; + private static final String MIN_SUPPORTED_GRADLE_VERSION = "8.6"; private static final int MIN_SUPPORTED_MAJOR_JAVA_VERSION = 17; private static final int MIN_SUPPORTED_MAJOR_IDEA_VERSION = 2021; diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0b2075ca..b715786e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -kotlin = "1.9.0" +kotlin = "1.9.20" asm = "9.6" commons-io = "2.15.1" gson = "2.10.1" @@ -11,7 +11,7 @@ access-widener = "2.1.0" mapping-io = "0.5.1" lorenz-tiny = "4.0.2" mercury = "0.4.1" -kotlinx-metadata = "0.8.0" +kotlinx-metadata = "0.9.0" # Plugins spotless = "6.20.0" diff --git a/gradle/test.libs.versions.toml b/gradle/test.libs.versions.toml index 08fa5b91..97e556b5 100644 --- a/gradle/test.libs.versions.toml +++ b/gradle/test.libs.versions.toml @@ -6,7 +6,7 @@ mockito = "5.8.0" java-debug = "0.50.0" mixin = "0.11.4+mixin.0.8.5" -gradle-nightly = "8.7-20240104001326+0000" +gradle-nightly = "8.7-20240202001338+0000" fabric-loader = "0.15.3" fabric-installer = "1.0.0" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d11cdd90..2ea3535d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java index 836138ba..15bb0cd4 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java @@ -25,6 +25,7 @@ package net.fabricmc.loom; import java.nio.file.Path; +import java.util.Collection; import java.util.List; import org.gradle.api.Project; @@ -38,12 +39,14 @@ import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.InstallerData; import net.fabricmc.loom.configuration.LoomDependencyManager; import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile; +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory; 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.extension.LoomFiles; +import net.fabricmc.loom.extension.LoomProblemReporter; import net.fabricmc.loom.extension.MixinExtension; import net.fabricmc.loom.extension.RemapperExtensionHolder; import net.fabricmc.loom.util.download.DownloadBuilder; @@ -118,4 +121,8 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { ListProperty getLibraryProcessors(); ListProperty getRemapperExtensions(); + + Collection getLayeredMappingFactories(); + + LoomProblemReporter getProblemReporter(); } diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index 041bc42d..302c9f93 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -53,6 +53,7 @@ import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor; import net.fabricmc.loom.configuration.ifaceinject.InterfaceInjectionProcessor; import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager; import net.fabricmc.loom.configuration.processors.ModJavadocProcessor; +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.MinecraftProvider; @@ -148,6 +149,9 @@ public abstract class CompileConfiguration implements Runnable { extension.setMinecraftProvider(minecraftProvider); minecraftProvider.provide(); + // Created any layered mapping files. + LayeredMappingsFactory.afterEvaluate(configContext); + final DependencyInfo mappingsDep = DependencyInfo.create(getProject(), Configurations.MAPPINGS); final MappingConfiguration mappingConfiguration = MappingConfiguration.create(getProject(), configContext.serviceManager(), mappingsDep, minecraftProvider); extension.setMappingConfiguration(mappingConfiguration); diff --git a/src/main/java/net/fabricmc/loom/configuration/DependencyInfo.java b/src/main/java/net/fabricmc/loom/configuration/DependencyInfo.java index 3c09e2bf..f186476d 100644 --- a/src/main/java/net/fabricmc/loom/configuration/DependencyInfo.java +++ b/src/main/java/net/fabricmc/loom/configuration/DependencyInfo.java @@ -32,8 +32,11 @@ import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; import org.gradle.api.artifacts.DependencySet; +import org.gradle.api.artifacts.FileCollectionDependency; import org.gradle.api.artifacts.ResolvedDependency; -import org.gradle.api.artifacts.SelfResolvingDependency; + +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.util.gradle.SelfResolvingDependencyUtils; public class DependencyInfo { final Project project; @@ -61,8 +64,11 @@ public class DependencyInfo { } public static DependencyInfo create(Project project, Dependency dependency, Configuration sourceConfiguration) { - if (dependency instanceof SelfResolvingDependency selfResolvingDependency) { - return new FileDependencyInfo(project, selfResolvingDependency, sourceConfiguration); + if (SelfResolvingDependencyUtils.isExplicitSRD(dependency)) { + LoomGradleExtension.get(project).getProblemReporter().reportSelfResolvingDependencyUsage(); + return FileDependencyInfo.createForDeprecatedSRD(project, dependency, sourceConfiguration); + } else if (dependency instanceof FileCollectionDependency fileCollectionDependency) { + return new FileDependencyInfo(project, fileCollectionDependency, sourceConfiguration); } else { return new DependencyInfo(project, dependency, sourceConfiguration); } @@ -99,10 +105,6 @@ public class DependencyInfo { } public Set resolve() { - if (dependency instanceof SelfResolvingDependency selfResolvingDependency) { - return selfResolvingDependency.resolve(); - } - return sourceConfiguration.files(dependency); } diff --git a/src/main/java/net/fabricmc/loom/configuration/FileDependencyInfo.java b/src/main/java/net/fabricmc/loom/configuration/FileDependencyInfo.java index 2f55bbe0..73bbc878 100644 --- a/src/main/java/net/fabricmc/loom/configuration/FileDependencyInfo.java +++ b/src/main/java/net/fabricmc/loom/configuration/FileDependencyInfo.java @@ -42,19 +42,24 @@ import org.apache.commons.io.FilenameUtils; import org.gradle.api.InvalidUserDataException; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.SelfResolvingDependency; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.FileCollectionDependency; import net.fabricmc.loom.util.ZipUtils; +import net.fabricmc.loom.util.gradle.SelfResolvingDependencyUtils; public class FileDependencyInfo extends DependencyInfo { protected final Map classifierToFile = new HashMap<>(); protected final Set resolvedFiles; protected final String group, name, version; - FileDependencyInfo(Project project, SelfResolvingDependency dependency, Configuration configuration) { + FileDependencyInfo(Project project, FileCollectionDependency dependency, Configuration configuration) { + this(project, dependency, configuration, dependency.getFiles().getFiles()); + } + + private FileDependencyInfo(Project project, Dependency dependency, Configuration configuration, Set files) { super(project, dependency, configuration); - Set files = dependency.resolve(); this.resolvedFiles = files; switch (files.size()) { case 0 -> //Don't think Gradle would ever let you do this @@ -126,6 +131,15 @@ public class FileDependencyInfo extends DependencyInfo { } } + @Deprecated // Remove in Gradle 9 + public static FileDependencyInfo createForDeprecatedSRD(Project project, Dependency dependency, Configuration configuration) { + if (!SelfResolvingDependencyUtils.isExplicitSRD(dependency)) { + throw new IllegalArgumentException("Dependency is a FileCollectionDependency"); + } + + return new FileDependencyInfo(project, dependency, configuration, SelfResolvingDependencyUtils.resolve(dependency)); + } + @Override public String getResolvedVersion() { return version; diff --git a/src/main/java/net/fabricmc/loom/configuration/mods/ArtifactRef.java b/src/main/java/net/fabricmc/loom/configuration/mods/ArtifactRef.java index 1e6798d0..b5c9ca8d 100644 --- a/src/main/java/net/fabricmc/loom/configuration/mods/ArtifactRef.java +++ b/src/main/java/net/fabricmc/loom/configuration/mods/ArtifactRef.java @@ -80,7 +80,7 @@ public interface ArtifactRef { public void applyToConfiguration(Project project, Configuration configuration) { final DependencyHandler dependencies = project.getDependencies(); - Dependency dep = dependencies.module(artifact.getModuleVersion() + (artifact.getClassifier() == null ? "" : ':' + artifact.getClassifier())); // the owning module of the artifact + Dependency dep = dependencies.create(artifact.getModuleVersion() + (artifact.getClassifier() == null ? "" : ':' + artifact.getClassifier())); // the owning module of the artifact if (dep instanceof ModuleDependency moduleDependency) { moduleDependency.setTransitive(false); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingSpecBuilderImpl.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingSpecBuilderImpl.java index 26dd21b9..1be17b7e 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingSpecBuilderImpl.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingSpecBuilderImpl.java @@ -85,4 +85,10 @@ public class LayeredMappingSpecBuilderImpl implements LayeredMappingSpecBuilder return new LayeredMappingSpec(Collections.unmodifiableList(builtLayers)); } + + public static LayeredMappingSpec buildOfficialMojangMappings() { + var builder = new LayeredMappingSpecBuilderImpl(); + builder.officialMojangMappings(); + return builder.build(); + } } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsDependency.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsFactory.java similarity index 62% rename from src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsDependency.java rename to src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsFactory.java index e99f4551..24058594 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsDependency.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsFactory.java @@ -24,9 +24,9 @@ package net.fabricmc.loom.configuration.providers.mappings; -import java.io.File; import java.io.IOException; import java.io.StringWriter; +import java.io.UncheckedIOException; import java.io.Writer; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -34,20 +34,18 @@ import java.nio.file.Path; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.Set; import org.gradle.api.Project; import org.gradle.api.artifacts.Dependency; -import org.gradle.api.artifacts.FileCollectionDependency; -import org.gradle.api.artifacts.SelfResolvingDependency; -import org.gradle.api.file.FileCollection; -import org.gradle.api.tasks.TaskDependency; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import net.fabricmc.loom.LoomGradlePlugin; import net.fabricmc.loom.api.mappings.layered.MappingContext; import net.fabricmc.loom.api.mappings.layered.MappingLayer; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.loom.configuration.ConfigContext; +import net.fabricmc.loom.configuration.mods.dependency.LocalMavenHelper; import net.fabricmc.loom.configuration.providers.mappings.extras.unpick.UnpickLayer; import net.fabricmc.loom.configuration.providers.mappings.utils.AddConstructorMappingVisitor; import net.fabricmc.loom.util.ZipUtils; @@ -56,43 +54,61 @@ import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; import net.fabricmc.mappingio.format.tiny.Tiny2FileWriter; import net.fabricmc.mappingio.tree.MemoryMappingTree; -public class LayeredMappingsDependency implements SelfResolvingDependency, FileCollectionDependency { +public record LayeredMappingsFactory(LayeredMappingSpec spec) { private static final String GROUP = "loom"; private static final String MODULE = "mappings"; + private static final Logger LOGGER = LoggerFactory.getLogger(LayeredMappingsFactory.class); - private final Project project; - private final MappingContext mappingContext; - private final LayeredMappingSpec layeredMappingSpec; - private final String version; - - public LayeredMappingsDependency(Project project, MappingContext mappingContext, LayeredMappingSpec layeredMappingSpec, String version) { - this.project = project; - this.mappingContext = mappingContext; - this.layeredMappingSpec = layeredMappingSpec; - this.version = version; - } - - @Override - public Set resolve() { - Path mappingsDir = mappingContext.minecraftProvider().dir("layered").toPath(); - Path mappingsFile = mappingsDir.resolve(String.format("%s.%s-%s.tiny", GROUP, MODULE, getVersion())); - - if (!Files.exists(mappingsFile) || mappingContext.refreshDeps()) { + /* + As we no longer have SelfResolvingDependency we now always create the mappings file after evaluation. + This works in a similar way to how remapped mods are handled. + */ + public static void afterEvaluate(ConfigContext configContext) { + for (LayeredMappingsFactory layeredMappingFactory : configContext.extension().getLayeredMappingFactories()) { try { - var processor = new LayeredMappingsProcessor(layeredMappingSpec); - List layers = processor.resolveLayers(mappingContext); - - Files.deleteIfExists(mappingsFile); - - writeMapping(processor, layers, mappingsFile); - writeSignatureFixes(processor, layers, mappingsFile); - writeUnpickData(processor, layers, mappingsFile); + layeredMappingFactory.evaluate(configContext); } catch (IOException e) { - throw new RuntimeException("Failed to resolve layered mappings", e); + throw new UncheckedIOException("Failed to setup layered mappings: %s".formatted(layeredMappingFactory.mavenNotation()), e); } } + } - return Collections.singleton(mappingsFile.toFile()); + private void evaluate(ConfigContext configContext) throws IOException { + LOGGER.info("Evaluating layer mapping: {}", mavenNotation()); + + final Path mavenRepoDir = configContext.extension().getFiles().getGlobalMinecraftRepo().toPath(); + final LocalMavenHelper maven = new LocalMavenHelper(GROUP, MODULE, spec().getVersion(), null, mavenRepoDir); + final Path jar = resolve(configContext.project()); + maven.copyToMaven(jar, null); + } + + public Path resolve(Project project) throws IOException { + final MappingContext mappingContext = new GradleMappingContext(project, spec.getVersion().replace("+", "_").replace(".", "_")); + final Path mappingsDir = mappingContext.minecraftProvider().dir("layered").toPath(); + final Path mappingsZip = mappingsDir.resolve(String.format("%s.%s-%s.jar", GROUP, MODULE, spec.getVersion())); + + if (Files.exists(mappingsZip) && !mappingContext.refreshDeps()) { + return mappingsZip; + } + + var processor = new LayeredMappingsProcessor(spec); + List layers = processor.resolveLayers(mappingContext); + + Files.deleteIfExists(mappingsZip); + + writeMapping(processor, layers, mappingsZip); + writeSignatureFixes(processor, layers, mappingsZip); + writeUnpickData(processor, layers, mappingsZip); + + return mappingsZip; + } + + public Dependency createDependency(Project project) { + return project.getDependencies().create(mavenNotation()); + } + + public String mavenNotation() { + return String.format("%s:%s:%s", GROUP, MODULE, spec.getVersion()); } private void writeMapping(LayeredMappingsProcessor processor, List layers, Path mappingsFile) throws IOException { @@ -133,57 +149,4 @@ public class LayeredMappingsDependency implements SelfResolvingDependency, FileC ZipUtils.add(mappingsFile, "extras/definitions.unpick", unpickData.definitions()); ZipUtils.add(mappingsFile, "extras/unpick.json", unpickData.metadata().asJson()); } - - @Override - public Set resolve(boolean transitive) { - return resolve(); - } - - @Override - public TaskDependency getBuildDependencies() { - return task -> Collections.emptySet(); - } - - @Override - public String getGroup() { - return GROUP; - } - - @Override - public String getName() { - return MODULE; - } - - @Override - public String getVersion() { - return version; - } - - @Override - public boolean contentEquals(Dependency dependency) { - if (dependency instanceof LayeredMappingsDependency layeredMappingsDependency) { - return Objects.equals(layeredMappingsDependency.getVersion(), this.getVersion()); - } - - return false; - } - - @Override - public Dependency copy() { - return new LayeredMappingsDependency(project, mappingContext, layeredMappingSpec, version); - } - - @Override - public String getReason() { - return null; - } - - @Override - public void because(String s) { - } - - @Override - public FileCollection getFiles() { - return project.files(resolve()); - } } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/utils/DependencyFileSpec.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/utils/DependencyFileSpec.java index 99c9d7d3..0eac2fe5 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/utils/DependencyFileSpec.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/utils/DependencyFileSpec.java @@ -30,21 +30,37 @@ import java.util.Objects; import java.util.Set; import org.gradle.api.artifacts.Dependency; -import org.gradle.api.artifacts.SelfResolvingDependency; +import org.gradle.api.artifacts.FileCollectionDependency; import net.fabricmc.loom.api.mappings.layered.MappingContext; import net.fabricmc.loom.api.mappings.layered.spec.FileSpec; +import net.fabricmc.loom.configuration.providers.mappings.GradleMappingContext; +import net.fabricmc.loom.util.gradle.SelfResolvingDependencyUtils; public record DependencyFileSpec(Dependency dependency) implements FileSpec { @Override public Path get(MappingContext context) { - if (dependency instanceof SelfResolvingDependency selfResolvingDependency) { - Set files = selfResolvingDependency.resolve(); + if (SelfResolvingDependencyUtils.isExplicitSRD(dependency)) { + if (context instanceof GradleMappingContext gradleMappingContext) { + gradleMappingContext.getExtension().getProblemReporter().reportSelfResolvingDependencyUsage(); + } - if (files.size() == 0) { - throw new RuntimeException("SelfResolvingDependency (%s) resolved no files".formatted(selfResolvingDependency.toString())); + Set files = SelfResolvingDependencyUtils.resolve(dependency); + + if (files.isEmpty()) { + throw new RuntimeException("SelfResolvingDependency (%s) resolved no files".formatted(dependency.toString())); } else if (files.size() > 1) { - throw new RuntimeException("SelfResolvingDependency (%s) resolved too many files (%d) only 1 is expected".formatted(selfResolvingDependency.toString(), files.size())); + throw new RuntimeException("SelfResolvingDependency (%s) resolved too many files (%d) only 1 is expected".formatted(dependency.toString(), files.size())); + } + + return files.iterator().next().toPath(); + } else if (dependency instanceof FileCollectionDependency fileCollectionDependency) { + Set files = fileCollectionDependency.getFiles().getFiles(); + + if (files.isEmpty()) { + throw new RuntimeException("FileCollectionDependency (%s) resolved no files".formatted(fileCollectionDependency.toString())); + } else if (files.size() > 1) { + throw new RuntimeException("FileCollectionDependency (%s) resolved too many files (%d) only 1 is expected".formatted(fileCollectionDependency.toString(), files.size())); } return files.iterator().next().toPath(); diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java index d9abf760..56d28ee6 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2021-2022 FabricMC + * Copyright (c) 2021-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 @@ -26,6 +26,8 @@ package net.fabricmc.loom.extension; import java.io.File; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import org.gradle.api.Action; @@ -59,10 +61,9 @@ import net.fabricmc.loom.api.remapping.RemapperParameters; import net.fabricmc.loom.configuration.RemapConfigurations; import net.fabricmc.loom.configuration.ide.RunConfigSettings; import net.fabricmc.loom.configuration.processors.JarProcessor; -import net.fabricmc.loom.configuration.providers.mappings.GradleMappingContext; import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec; import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilderImpl; -import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsDependency; +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets; import net.fabricmc.loom.task.GenerateSourcesTask; @@ -102,6 +103,9 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA // A common mistake with layered mappings is to call the wrong `officialMojangMappings` method, use this to keep track of when we are building a layered mapping spec. protected final ThreadLocal layeredSpecBuilderScope = ThreadLocal.withInitial(() -> false); + protected boolean hasEvaluatedLayeredMappings = false; + protected final Map layeredMappingsDependencyMap = new HashMap<>(); + protected LoomGradleExtensionApiImpl(Project project, LoomFiles directories) { this.jarProcessors = project.getObjects().listProperty(JarProcessor.class) .empty(); @@ -210,14 +214,19 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA @Override public Dependency layered(Action action) { + if (hasEvaluatedLayeredMappings) { + throw new IllegalStateException("Layered mappings have already been evaluated"); + } + LayeredMappingSpecBuilderImpl builder = new LayeredMappingSpecBuilderImpl(); layeredSpecBuilderScope.set(true); action.execute(builder); layeredSpecBuilderScope.set(false); - LayeredMappingSpec builtSpec = builder.build(); - return new LayeredMappingsDependency(getProject(), new GradleMappingContext(getProject(), builtSpec.getVersion().replace("+", "_").replace(".", "_")), builtSpec, builtSpec.getVersion()); + final LayeredMappingSpec builtSpec = builder.build(); + final LayeredMappingsFactory layeredMappingsFactory = layeredMappingsDependencyMap.computeIfAbsent(builtSpec, LayeredMappingsFactory::new); + return layeredMappingsFactory.createDependency(getProject()); } @Override diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java index 7fe809fc..382fbc14 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2021 FabricMC + * Copyright (c) 2021-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 @@ -27,6 +27,8 @@ package net.fabricmc.loom.extension; import java.net.URISyntaxException; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -43,6 +45,7 @@ import net.fabricmc.loom.configuration.InstallerData; import net.fabricmc.loom.configuration.LoomDependencyManager; import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile; import net.fabricmc.loom.configuration.providers.mappings.IntermediaryMappingsProvider; +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory; 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; @@ -70,6 +73,7 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen private boolean refreshDeps; private Provider multiProjectOptimisation; private final ListProperty libraryProcessorFactories; + private final LoomProblemReporter problemReporter; public LoomGradleExtensionImpl(Project project, LoomFiles files) { super(project, files); @@ -97,6 +101,8 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen if (refreshDeps) { project.getLogger().lifecycle("Refresh dependencies is in use, loom will be significantly slower."); } + + problemReporter = project.getObjects().newInstance(LoomProblemReporter.class); } @Override @@ -252,6 +258,12 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen return remapperExtensions; } + @Override + public Collection getLayeredMappingFactories() { + hasEvaluatedLayeredMappings = true; + return Collections.unmodifiableCollection(layeredMappingsDependencyMap.values()); + } + @Override protected void configureIntermediateMappingsProviderInternal(T provider) { provider.getMinecraftVersion().set(getProject().provider(() -> getMinecraftProvider().minecraftVersion())); @@ -260,4 +272,9 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen provider.getDownloader().set(this::download); provider.getDownloader().disallowChanges(); } + + @Override + public LoomProblemReporter getProblemReporter() { + return problemReporter; + } } diff --git a/src/main/java/net/fabricmc/loom/extension/LoomProblemReporter.java b/src/main/java/net/fabricmc/loom/extension/LoomProblemReporter.java new file mode 100644 index 00000000..d8eee138 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/extension/LoomProblemReporter.java @@ -0,0 +1,51 @@ +/* + * 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.extension; + +import javax.inject.Inject; + +import org.gradle.api.problems.ProblemReporter; +import org.gradle.api.problems.Problems; +import org.gradle.api.problems.Severity; + +public abstract class LoomProblemReporter { + private final ProblemReporter problemReporter; + + @Inject + public LoomProblemReporter(Problems problems) { + this.problemReporter = problems.forNamespace("net.fabricmc.loom"); + } + + public void reportSelfResolvingDependencyUsage() { + problemReporter.reporting(spec -> spec + .label("SelfResolvingDependency is deprecated") + .details("SelfResolvingDependency has been deprecated for removal in Gradle 9") + .solution("Please replace usages of SelfResolvingDependency") + .documentedAt("https://github.com/gradle/gradle/pull/27420") + .severity(Severity.WARNING) + .stackLocation() + ); + } +} diff --git a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java index 64e55626..d40bd3dd 100644 --- a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java +++ b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java @@ -26,8 +26,10 @@ package net.fabricmc.loom.task; import java.io.File; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; import java.util.Set; import com.google.common.collect.ImmutableMap; @@ -50,8 +52,8 @@ import org.gradle.work.DisableCachingByDefault; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; -import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder; -import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsDependency; +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilderImpl; +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory; import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration; import net.fabricmc.loom.util.FileSystemUtil; import net.fabricmc.loom.util.SourceRemapper; @@ -133,8 +135,8 @@ public abstract class MigrateMappingsTask extends AbstractLoomTask { throw new UnsupportedOperationException("Migrating Mojang mappings is currently only supported for the specified minecraft version"); } - LayeredMappingsDependency dep = (LayeredMappingsDependency) getExtension().layered(LayeredMappingSpecBuilder::officialMojangMappings); - files = dep.resolve(); + LayeredMappingsFactory dep = new LayeredMappingsFactory(LayeredMappingSpecBuilderImpl.buildOfficialMojangMappings()); + files = Collections.singleton(dep.resolve(getProject()).toFile()); } else { Dependency dependency = project.getDependencies().create(mappings); files = project.getConfigurations().detachedConfiguration(dependency).resolve(); @@ -143,11 +145,13 @@ public abstract class MigrateMappingsTask extends AbstractLoomTask { project.getLogger().info("Could not locate mappings, presuming V2 Yarn"); try { - files = project.getConfigurations().detachedConfiguration(project.getDependencies().module(ImmutableMap.of("group", "net.fabricmc", "name", "yarn", "version", mappings, "classifier", "v2"))).resolve(); + files = project.getConfigurations().detachedConfiguration(project.getDependencies().create(ImmutableMap.of("group", "net.fabricmc", "name", "yarn", "version", mappings, "classifier", "v2"))).resolve(); } catch (GradleException ignored2) { project.getLogger().info("Could not locate mappings, presuming V1 Yarn"); - files = project.getConfigurations().detachedConfiguration(project.getDependencies().module(ImmutableMap.of("group", "net.fabricmc", "name", "yarn", "version", mappings))).resolve(); + files = project.getConfigurations().detachedConfiguration(project.getDependencies().create(ImmutableMap.of("group", "net.fabricmc", "name", "yarn", "version", mappings))).resolve(); } + } catch (IOException e) { + throw new UncheckedIOException("Failed to resolve mappings", e); } if (files.isEmpty()) { diff --git a/src/main/java/net/fabricmc/loom/util/gradle/SelfResolvingDependencyUtils.java b/src/main/java/net/fabricmc/loom/util/gradle/SelfResolvingDependencyUtils.java new file mode 100644 index 00000000..cfbddd98 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/util/gradle/SelfResolvingDependencyUtils.java @@ -0,0 +1,114 @@ +/* + * 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.util.gradle; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Set; + +import javax.annotation.Nullable; + +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.FileCollectionDependency; +import org.gradle.api.artifacts.ProjectDependency; + +// SelfResolvingDependency is deprecated for removal, use reflection to ensure backwards compat. +@Deprecated +public class SelfResolvingDependencyUtils { + // Set this system prop to disable SRD support before Gradle does. + public static final boolean DISABLE_SRD_SUPPORT = System.getProperty("fabric.loom.disable.srd") != null; + + private static final String SELF_RESOLVING_DEPENDENCY_CLASS_NAME = "org.gradle.api.artifacts.SelfResolvingDependency"; + @Nullable + private static final Class SELF_RESOLVING_DEPENDENCY_CLASS = getSelfResolvingDependencyOrNull(); + @Nullable + private static final Method RESOLVE_METHOD = getResolveMethod(SELF_RESOLVING_DEPENDENCY_CLASS); + + /** + * @return true when dependency is a SelfResolvingDependency but NOT a FileCollectionDependency. + */ + public static boolean isExplicitSRD(Dependency dependency) { + // FileCollectionDependency is usually the replacement for SelfResolvingDependency + if (dependency instanceof FileCollectionDependency) { + return false; + } else if (dependency instanceof ProjectDependency) { + return false; + } + + return isSRD(dependency); + } + + private static boolean isSRD(Dependency dependency) { + if (SELF_RESOLVING_DEPENDENCY_CLASS == null) { + return false; + } + + return dependency.getClass().isAssignableFrom(SELF_RESOLVING_DEPENDENCY_CLASS); + } + + public static Set resolve(Dependency dependency) { + if (!isSRD(dependency)) { + throw new IllegalStateException("dependency is not a SelfResolvingDependency"); + } + + try { + return (Set) RESOLVE_METHOD.invoke(dependency); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Failed to resolve SelfResolvingDependency", e); + } + } + + @Nullable + private static Class getSelfResolvingDependencyOrNull() { + if (DISABLE_SRD_SUPPORT) { + // Lets pretend SRD doesnt exist. + return null; + } + + try { + return Class.forName(SELF_RESOLVING_DEPENDENCY_CLASS_NAME); + } catch (ClassNotFoundException e) { + // Gradle 9+ + return null; + } + } + + @Nullable + private static Method getResolveMethod(Class clazz) { + if (clazz == null) { + // Gradle 9+ + return null; + } + + try { + var method = clazz.getDeclaredMethod("resolve"); + method.setAccessible(true); + return method; + } catch (NoSuchMethodException e) { + throw new IllegalStateException("Failed to get SelfResolvingDependency.resolve() method", e); + } + } +} diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/KotlinTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/KotlinTest.groovy index 93a8140c..5b59c390 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/KotlinTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/KotlinTest.groovy @@ -40,7 +40,7 @@ class KotlinTest extends Specification implements GradleProjectTestTrait { def gradle = gradleProject(project: "kotlin", version: version) def server = ServerRunner.create(gradle.projectDir, "1.16.5") .withMod(gradle.getOutputFile("fabric-example-mod-0.0.1.jar")) - .downloadMod(ServerRunner.FABRIC_LANG_KOTLIN, "fabric-language-kotlin-1.8.7+kotlin.1.7.22.jar") + .downloadMod(ServerRunner.FABRIC_LANG_KOTLIN, "fabric-language-kotlin-1.10.17+kotlin.1.9.22.jar") when: def result = gradle.run(tasks: [ diff --git a/src/test/resources/projects/kotlin/build.gradle.kts b/src/test/resources/projects/kotlin/build.gradle.kts index 7f2e0f5d..75a1015d 100644 --- a/src/test/resources/projects/kotlin/build.gradle.kts +++ b/src/test/resources/projects/kotlin/build.gradle.kts @@ -1,8 +1,10 @@ import java.util.Properties +import org.jetbrains.kotlin.gradle.dsl.KotlinCompile +import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions plugins { - kotlin("jvm") version "1.7.22" - kotlin("plugin.serialization") version "1.7.22" + kotlin("jvm") version "1.9.22" + kotlin("plugin.serialization") version "1.9.22" id("fabric-loom") `maven-publish` } @@ -12,6 +14,17 @@ java { targetCompatibility = JavaVersion.VERSION_1_8 } +tasks { + withType { + options.release.set(8) + } + withType> { + kotlinOptions { + jvmTarget = "1.8" + } + } +} + group = "com.example" version = "0.0.1" @@ -19,7 +32,7 @@ dependencies { minecraft(group = "com.mojang", name = "minecraft", version = "1.16.5") mappings(group = "net.fabricmc", name = "yarn", version = "1.16.5+build.5", classifier = "v2") modImplementation("net.fabricmc:fabric-loader:0.12.12") - modImplementation(group = "net.fabricmc", name = "fabric-language-kotlin", version = "1.8.7+kotlin.1.7.22") + modImplementation(group = "net.fabricmc", name = "fabric-language-kotlin", version = "1.10.17+kotlin.1.9.22") } publishing {