From 33ade3bdd64fa63dfd1d8441dc9cd37eb71c45b7 Mon Sep 17 00:00:00 2001 From: Marc Hermans Date: Fri, 17 May 2024 12:49:55 +0200 Subject: [PATCH 1/2] Resolve the issue where Mixin Extras does not appear on the CP Add support for rich versions Closes: #84 --- .../replacement/ReplacementLogic.java | 9 +- .../extensions/repository/IvyRepository.java | 7 +- .../replacement/ReplacementAware.groovy | 9 ++ .../dsl/userdev/extension/UserDev.groovy | 37 ------ .../gradle/userdev/FunctionalTests.groovy | 119 ++++++++++++++++++ .../gradle/userdev/UserDevProjectPlugin.java | 3 - .../dependency/UserDevDependencyManager.java | 35 +++--- .../dependency/UserDevReplacementResult.java | 15 +++ .../userdev/extension/UserDevExtension.java | 25 ---- .../UserDevRuntimeSpecification.java | 26 ---- 10 files changed, 173 insertions(+), 112 deletions(-) delete mode 100644 dsl/userdev/src/main/groovy/net/neoforged/gradle/dsl/userdev/extension/UserDev.groovy delete mode 100644 userdev/src/main/java/net/neoforged/gradle/userdev/extension/UserDevExtension.java diff --git a/common/src/main/java/net/neoforged/gradle/common/extensions/dependency/replacement/ReplacementLogic.java b/common/src/main/java/net/neoforged/gradle/common/extensions/dependency/replacement/ReplacementLogic.java index 827ebf7d0..1fb4969d5 100644 --- a/common/src/main/java/net/neoforged/gradle/common/extensions/dependency/replacement/ReplacementLogic.java +++ b/common/src/main/java/net/neoforged/gradle/common/extensions/dependency/replacement/ReplacementLogic.java @@ -335,7 +335,14 @@ Entry createDummyDependency(final Dependency dependency, final ReplacementResult } // Create a new repository entry for the dependency, using the replacement result. - final ExternalModuleDependency externalModuleDependency = (ExternalModuleDependency) dependency; + ExternalModuleDependency externalModuleDependency = (ExternalModuleDependency) dependency; + //Check if the result is replacement aware. + if (result instanceof ReplacementAware) { + final ReplacementAware replacementAware = (ReplacementAware) result; + //Let it alter the dependency, this allows support for version ranges, and strict versioning. + externalModuleDependency = replacementAware.getReplacementDependency(externalModuleDependency); + } + final Repository extension = project.getExtensions().getByType(Repository.class); return extension.withEntry( project.getObjects().newInstance( diff --git a/common/src/main/java/net/neoforged/gradle/common/extensions/repository/IvyRepository.java b/common/src/main/java/net/neoforged/gradle/common/extensions/repository/IvyRepository.java index b3c312573..d3dec21ee 100644 --- a/common/src/main/java/net/neoforged/gradle/common/extensions/repository/IvyRepository.java +++ b/common/src/main/java/net/neoforged/gradle/common/extensions/repository/IvyRepository.java @@ -61,10 +61,15 @@ public Project getProject() { } private ArtifactRepository createRepositories() { - return project.getRepositories().ivy(repositoryConfiguration( + final ArtifactRepository repository = project.getRepositories().ivy(repositoryConfiguration( "NeoGradle Artifacts", getRepositoryDirectory() )); + + project.getRepositories().remove(repository); + project.getRepositories().addFirst(repository); + + return repository; } @Override diff --git a/dsl/common/src/main/groovy/net/neoforged/gradle/dsl/common/extensions/dependency/replacement/ReplacementAware.groovy b/dsl/common/src/main/groovy/net/neoforged/gradle/dsl/common/extensions/dependency/replacement/ReplacementAware.groovy index 212934d31..c610736f5 100644 --- a/dsl/common/src/main/groovy/net/neoforged/gradle/dsl/common/extensions/dependency/replacement/ReplacementAware.groovy +++ b/dsl/common/src/main/groovy/net/neoforged/gradle/dsl/common/extensions/dependency/replacement/ReplacementAware.groovy @@ -1,6 +1,7 @@ package net.neoforged.gradle.dsl.common.extensions.dependency.replacement import net.neoforged.gradle.dsl.common.tasks.WithOutput +import org.gradle.api.artifacts.ExternalModuleDependency import org.gradle.api.tasks.TaskProvider /** @@ -18,4 +19,12 @@ interface ReplacementAware { TaskProvider copiesRawJar, TaskProvider copiesMappedJar ); + + /** + * Gets the replacement dependency for the given dependency. + * + * @param externalModuleDependency The dependency to get the replacement for. + * @return The replacement dependency. + */ + ExternalModuleDependency getReplacementDependency(ExternalModuleDependency externalModuleDependency) } diff --git a/dsl/userdev/src/main/groovy/net/neoforged/gradle/dsl/userdev/extension/UserDev.groovy b/dsl/userdev/src/main/groovy/net/neoforged/gradle/dsl/userdev/extension/UserDev.groovy deleted file mode 100644 index 7e2dae7c8..000000000 --- a/dsl/userdev/src/main/groovy/net/neoforged/gradle/dsl/userdev/extension/UserDev.groovy +++ /dev/null @@ -1,37 +0,0 @@ -package net.neoforged.gradle.dsl.userdev.extension - -import groovy.transform.CompileStatic -import net.minecraftforge.gdi.BaseDSLElement -import net.minecraftforge.gdi.annotations.DSLProperty; -import org.gradle.api.provider.Property; - -/** - * Defines a user dev extension within the confines of a forge-based project. - */ -@CompileStatic -interface UserDev extends BaseDSLElement { - - /** - * Defines the default forge version to use for the project. - * - * @return The default forge version to use for the project. - */ - @DSLProperty - Property getDefaultForgeVersion(); - - /** - * Defines the default forge group to use for the project. - * - * @return The default forge group to use for the project. - */ - @DSLProperty - Property getDefaultForgeGroup(); - - /** - * Defines the default forge artifact name to use for the project. - * - * @return The default forge artifact name to use for the project. - */ - @DSLProperty - Property getDefaultForgeName(); -} diff --git a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/FunctionalTests.groovy b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/FunctionalTests.groovy index 9f63d1d0c..f81688f4b 100644 --- a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/FunctionalTests.groovy +++ b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/FunctionalTests.groovy @@ -38,6 +38,125 @@ class FunctionalTests extends BuilderBasedTestSpecification { run.task(':neoFormRecompile').outcome == TaskOutcome.SUCCESS } + def "userdev supports version range resolution"() { + given: + def project = create("userdev_supports_version_ranges", { + it.build(""" + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + dependencies { + implementation 'net.neoforged:neoforge:[20,)' + } + """) + it.file("src/main/java/net/neoforged/gradle/userdev/FunctionalTests.java", """ + package net.neoforged.gradle.userdev; + + import net.minecraft.client.Minecraft; + + public class FunctionalTests { + public static void main(String[] args) { + System.out.println(Minecraft.getInstance().getClass().toString()); + } + } + """) + it.withToolchains() + }) + + when: + def run = project.run { + it.tasks('dependencies', "--configuration", "compileClasspath") + } + + then: + run.task(':dependencies').outcome == TaskOutcome.SUCCESS + run.output.contains("\\--- net.neoforged:neoforge:") + } + + def "userdev supports complex version resolution"() { + given: + def project = create("userdev_supports_complex_versions", { + it.build(""" + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + dependencies { + implementation ('net.neoforged:neoforge') { + version { + strictly '[20.4.167, 20.5)' + require '20.4.188' + } + } + } + """) + it.file("src/main/java/net/neoforged/gradle/userdev/FunctionalTests.java", """ + package net.neoforged.gradle.userdev; + + import net.minecraft.client.Minecraft; + + public class FunctionalTests { + public static void main(String[] args) { + System.out.println(Minecraft.getInstance().getClass().toString()); + } + } + """) + it.withToolchains() + }) + + when: + def run = project.run { + it.tasks('dependencies', "--configuration", "compileClasspath") + } + + then: + run.task(':dependencies').outcome == TaskOutcome.SUCCESS + run.output.contains("\\--- net.neoforged:neoforge:20.4.188") + } + + def "a mod with userdev as dependency has a mixin-extra dependency on the compile classpath"() { + given: + def project = create("userdev_adds_mixin_extra_on_compile_classpath", { + it.build(""" + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + dependencies { + implementation 'net.neoforged:neoforge:+' + } + """) + it.file("src/main/java/net/neoforged/gradle/userdev/FunctionalTests.java", """ + package net.neoforged.gradle.userdev; + + import net.minecraft.client.Minecraft; + + public class FunctionalTests { + public static void main(String[] args) { + System.out.println(Minecraft.getInstance().getClass().toString()); + } + } + """) + it.withToolchains() + }) + + when: + def run = project.run { + it.tasks('dependencies', "--configuration", "compileClasspath") + } + + then: + run.task(':dependencies').outcome == TaskOutcome.SUCCESS + run.output.contains("+--- io.github.llamalad7:mixinextras-neoforge") + } + def "a mod with userdev as dependency and official mappings can compile through gradle"() { given: def project = create("compile_with_gradle_and_official_mappings", { diff --git a/userdev/src/main/java/net/neoforged/gradle/userdev/UserDevProjectPlugin.java b/userdev/src/main/java/net/neoforged/gradle/userdev/UserDevProjectPlugin.java index 7bcf247f7..afbc5ec34 100644 --- a/userdev/src/main/java/net/neoforged/gradle/userdev/UserDevProjectPlugin.java +++ b/userdev/src/main/java/net/neoforged/gradle/userdev/UserDevProjectPlugin.java @@ -3,10 +3,8 @@ import net.neoforged.gradle.common.extensions.DefaultJarJarFeature; import net.neoforged.gradle.common.extensions.JarJarExtension; import net.neoforged.gradle.dsl.common.extensions.JarJar; -import net.neoforged.gradle.dsl.userdev.extension.UserDev; import net.neoforged.gradle.neoform.NeoFormPlugin; import net.neoforged.gradle.userdev.dependency.UserDevDependencyManager; -import net.neoforged.gradle.userdev.extension.UserDevExtension; import net.neoforged.gradle.userdev.runtime.extension.UserDevRuntimeExtension; import org.gradle.api.Plugin; import org.gradle.api.Project; @@ -22,7 +20,6 @@ public class UserDevProjectPlugin implements Plugin { public void apply(Project project) { project.getPlugins().apply(NeoFormPlugin.class); - project.getExtensions().create(UserDev.class, "userDev", UserDevExtension.class, project); project.getExtensions().create("userDevRuntime", UserDevRuntimeExtension.class, project); UserDevDependencyManager.getInstance().apply(project); diff --git a/userdev/src/main/java/net/neoforged/gradle/userdev/dependency/UserDevDependencyManager.java b/userdev/src/main/java/net/neoforged/gradle/userdev/dependency/UserDevDependencyManager.java index edafcc173..f752ddae8 100644 --- a/userdev/src/main/java/net/neoforged/gradle/userdev/dependency/UserDevDependencyManager.java +++ b/userdev/src/main/java/net/neoforged/gradle/userdev/dependency/UserDevDependencyManager.java @@ -1,20 +1,12 @@ package net.neoforged.gradle.userdev.dependency; -import com.google.common.collect.Sets; -import net.neoforged.gradle.dsl.common.util.ConfigurationUtils; import net.neoforged.gradle.dsl.common.extensions.dependency.replacement.DependencyReplacement; -import net.neoforged.gradle.dsl.common.extensions.dependency.replacement.ReplacementResult; -import net.neoforged.gradle.dsl.common.util.CommonRuntimeUtils; +import net.neoforged.gradle.dsl.common.util.ConfigurationUtils; import net.neoforged.gradle.dsl.common.util.DistributionType; -import net.neoforged.gradle.dsl.userdev.extension.UserDev; import net.neoforged.gradle.userdev.runtime.definition.UserDevRuntimeDefinition; import net.neoforged.gradle.userdev.runtime.extension.UserDevRuntimeExtension; import org.gradle.api.Project; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.Dependency; -import org.gradle.api.artifacts.DependencyArtifact; -import org.gradle.api.artifacts.ExternalModuleDependency; -import org.gradle.api.provider.Provider; +import org.gradle.api.artifacts.*; import java.util.Collections; import java.util.Objects; @@ -97,16 +89,21 @@ private static boolean hasSourcesArtifact(ExternalModuleDependency externalModul private static UserDevRuntimeDefinition buildForgeUserDevRuntimeFrom(Project project, ExternalModuleDependency dependency) { final UserDevRuntimeExtension forgeRuntimeExtension = project.getExtensions().getByType(UserDevRuntimeExtension.class); - final UserDev userDevExtension = project.getExtensions().getByType(UserDev.class); - + return forgeRuntimeExtension.maybeCreateFor(dependency, builder -> { - final Provider version = project.provider(dependency::getVersion).orElse(userDevExtension.getDefaultForgeVersion()); - final Provider group = project.provider(dependency::getGroup).orElse(userDevExtension.getDefaultForgeGroup()); - final Provider name = project.provider(dependency::getName).orElse(userDevExtension.getDefaultForgeName()); - - builder.withForgeVersion(version); - builder.withForgeGroup(group); - builder.withForgeName(name); + + final ExternalModuleDependency clone = dependency.copy(); + clone.artifact(artifact -> { + artifact.setExtension("jar"); + artifact.setClassifier("userdev"); + }); + + final Configuration userdevLookup = ConfigurationUtils.temporaryUnhandledConfiguration(project.getConfigurations(), "ResolveRequestedNeoForgeVersion", clone); + final ResolvedArtifact resolvedArtifact = userdevLookup.getResolvedConfiguration().getFirstLevelModuleDependencies().iterator().next().getModuleArtifacts().iterator().next(); + + builder.withForgeVersion(resolvedArtifact.getModuleVersion().getId().getVersion()); + builder.withForgeGroup(resolvedArtifact.getModuleVersion().getId().getGroup()); + builder.withForgeName(resolvedArtifact.getModuleVersion().getId().getName()); builder.withDistributionType(DistributionType.JOINED); }); } diff --git a/userdev/src/main/java/net/neoforged/gradle/userdev/dependency/UserDevReplacementResult.java b/userdev/src/main/java/net/neoforged/gradle/userdev/dependency/UserDevReplacementResult.java index 81ae91ce2..b313079a5 100644 --- a/userdev/src/main/java/net/neoforged/gradle/userdev/dependency/UserDevReplacementResult.java +++ b/userdev/src/main/java/net/neoforged/gradle/userdev/dependency/UserDevReplacementResult.java @@ -7,6 +7,8 @@ import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.ExternalModuleDependency; import org.gradle.api.tasks.TaskProvider; import org.jetbrains.annotations.Nullable; @@ -36,4 +38,17 @@ public void onTasksCreated(TaskProvider copiesRawJar, Task //Register the classpath element producer definition.setUserdevClasspathElementProducer(copiesRawJar); } + + @Override + public ExternalModuleDependency getReplacementDependency(ExternalModuleDependency externalModuleDependency) { + final Dependency resolvedExactVersionDependency = getProject().getDependencies() + .create( + definition.getSpecification().getForgeGroup() + ":" + definition.getSpecification().getForgeName() + ":" + definition.getSpecification().getForgeVersion() + ); + + if (!(resolvedExactVersionDependency instanceof ExternalModuleDependency)) + throw new IllegalStateException("Resolved dependency is not an ExternalModuleDependency"); + + return (ExternalModuleDependency) resolvedExactVersionDependency; + } } diff --git a/userdev/src/main/java/net/neoforged/gradle/userdev/extension/UserDevExtension.java b/userdev/src/main/java/net/neoforged/gradle/userdev/extension/UserDevExtension.java deleted file mode 100644 index fec6506b5..000000000 --- a/userdev/src/main/java/net/neoforged/gradle/userdev/extension/UserDevExtension.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.neoforged.gradle.userdev.extension; - -import net.minecraftforge.gdi.ConfigurableDSLElement; -import net.neoforged.gradle.dsl.userdev.extension.UserDev; -import org.gradle.api.Project; - -import javax.inject.Inject; - -public abstract class UserDevExtension implements UserDev, ConfigurableDSLElement { - - private final Project project; - - @Inject - public UserDevExtension(Project project) { - this.project = project; - - this.getDefaultForgeName().convention("neoforge"); - this.getDefaultForgeGroup().convention("net.neoforged"); - } - - @Override - public Project getProject() { - return project; - } -} diff --git a/userdev/src/main/java/net/neoforged/gradle/userdev/runtime/specification/UserDevRuntimeSpecification.java b/userdev/src/main/java/net/neoforged/gradle/userdev/runtime/specification/UserDevRuntimeSpecification.java index 019dddbd9..1b86a4e96 100644 --- a/userdev/src/main/java/net/neoforged/gradle/userdev/runtime/specification/UserDevRuntimeSpecification.java +++ b/userdev/src/main/java/net/neoforged/gradle/userdev/runtime/specification/UserDevRuntimeSpecification.java @@ -8,7 +8,6 @@ import net.neoforged.gradle.dsl.common.util.Artifact; import net.neoforged.gradle.dsl.common.util.DistributionType; import net.neoforged.gradle.dsl.userdev.configurations.UserdevProfile; -import net.neoforged.gradle.dsl.userdev.extension.UserDev; import net.neoforged.gradle.dsl.userdev.runtime.specification.UserDevSpecification; import net.neoforged.gradle.userdev.runtime.extension.UserDevRuntimeExtension; import net.neoforged.gradle.util.FileUtils; @@ -18,7 +17,6 @@ import org.gradle.api.artifacts.ModuleVersionIdentifier; import org.gradle.api.artifacts.ResolvedArtifact; import org.gradle.api.file.FileTree; -import org.gradle.api.file.RegularFileProperty; import org.gradle.api.provider.Provider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -106,9 +104,6 @@ public int hashCode() { public static final class Builder extends CommonRuntimeSpecification.Builder implements UserDevSpecification.Builder { - private boolean hasConfiguredForgeVersion; - private boolean hasConfiguredForgeName; - private boolean hasConfiguredForgeGroup; private Provider forgeVersionProvider; private Provider forgeGroupProvider; private Provider forgeNameProvider; @@ -126,28 +121,9 @@ public static Builder from(final Project project) { return new Builder(project); } - @Override - protected void configureBuilder() { - super.configureBuilder(); - final UserDev runtimeExtension = getProject().getExtensions().getByType(UserDev.class); - - if (!hasConfiguredForgeVersion) { - forgeVersionProvider = runtimeExtension.getDefaultForgeVersion(); - } - - if (!hasConfiguredForgeGroup) { - forgeGroupProvider = runtimeExtension.getDefaultForgeGroup(); - } - - if (!hasConfiguredForgeName) { - forgeNameProvider = runtimeExtension.getDefaultForgeName(); - } - } - @Override public Builder withForgeVersion(final Provider forgeVersion) { this.forgeVersionProvider = forgeVersion; - this.hasConfiguredForgeVersion = true; return this; } @@ -162,7 +138,6 @@ public Builder withForgeVersion(final String forgeVersion) { @Override public Builder withForgeName(final Provider mcpName) { this.forgeNameProvider = mcpName; - this.hasConfiguredForgeName = true; return this; } @@ -177,7 +152,6 @@ public Builder withForgeName(final String mcpName) { @Override public Builder withForgeGroup(final Provider mcpGroup) { this.forgeGroupProvider = mcpGroup; - this.hasConfiguredForgeGroup = true; return this; } From f30a7352ae0a08817ded8e0239057a174215048c Mon Sep 17 00:00:00 2001 From: Marc Hermans Date: Fri, 17 May 2024 12:55:19 +0200 Subject: [PATCH 2/2] Clean up platform project plugin. --- .../neoforged/gradle/platform/PlatformProjectPlugin.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/platform/src/main/java/net/neoforged/gradle/platform/PlatformProjectPlugin.java b/platform/src/main/java/net/neoforged/gradle/platform/PlatformProjectPlugin.java index 11c7368f3..608806225 100644 --- a/platform/src/main/java/net/neoforged/gradle/platform/PlatformProjectPlugin.java +++ b/platform/src/main/java/net/neoforged/gradle/platform/PlatformProjectPlugin.java @@ -5,12 +5,7 @@ import net.neoforged.gradle.common.util.constants.RunsConstants; import net.neoforged.gradle.dsl.common.runs.ide.extensions.IdeaRunExtension; import net.neoforged.gradle.dsl.common.runs.run.Run; -import net.neoforged.gradle.dsl.userdev.extension.UserDev; -import net.neoforged.gradle.neoform.NeoFormPlugin; import net.neoforged.gradle.platform.extensions.DynamicProjectExtension; -import net.neoforged.gradle.platform.runtime.runtime.definition.RuntimeDevRuntimeDefinition; -import net.neoforged.gradle.userdev.extension.UserDevExtension; -import net.neoforged.gradle.userdev.runtime.extension.UserDevRuntimeExtension; import org.gradle.api.Action; import org.gradle.api.NamedDomainObjectContainer; import org.gradle.api.Plugin; @@ -45,8 +40,4 @@ private void configureRun(final Project project, final Run run) { project.getExtensions().getByType(IdeManagementExtension.class).onIdea((project1, idea, ideaExtension) -> run.getExtensions().getByType(IdeaRunExtension.class).getPrimarySourceSet().convention(mainSourceSet)); } - - private Provider buildModClasses(final Project project, final Run run) { - return project.provider(() -> Stream.concat(run.getModSources().get().stream().map(source -> source.getOutput().getResourcesDir()), run.getModSources().get().stream().map(source -> source.getOutput().getClassesDirs().getFiles()).flatMap(Collection::stream)).map(File::getAbsolutePath).map(path -> String.format("minecraft%%%%%s", path)).collect(Collectors.joining(File.pathSeparator))); - } }