diff --git a/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java b/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java index c87bc230..4f21ff6c 100644 --- a/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java +++ b/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java @@ -153,6 +153,10 @@ public void apply(Project project) { //Set up reporting tasks project.getTasks().register("runs", RunsReport.class); + //Configure sdk configurations + final SourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class); + sourceSets.all(ConfigurationUtils::getSdkConfiguration); + //Needs to be before after evaluate ConventionConfigurator.configureConventions(project); diff --git a/common/src/main/java/net/neoforged/gradle/common/conventions/ConventionConfigurator.java b/common/src/main/java/net/neoforged/gradle/common/conventions/ConventionConfigurator.java index 99620861..e2decf86 100644 --- a/common/src/main/java/net/neoforged/gradle/common/conventions/ConventionConfigurator.java +++ b/common/src/main/java/net/neoforged/gradle/common/conventions/ConventionConfigurator.java @@ -10,6 +10,7 @@ import net.neoforged.gradle.dsl.common.extensions.subsystems.conventions.Runs; import net.neoforged.gradle.dsl.common.extensions.subsystems.conventions.SourceSets; import net.neoforged.gradle.dsl.common.extensions.subsystems.conventions.ide.IDEA; +import net.neoforged.gradle.dsl.common.runs.run.Run; import net.neoforged.gradle.dsl.common.runs.run.RunManager; import org.gradle.StartParameter; import org.gradle.TaskExecutionRequest; @@ -62,11 +63,23 @@ private static void configureRunConventions(Project project, Conventions convent final Configuration runRuntimeConfiguration = project.getConfigurations().maybeCreate(configurations.getRunRuntimeConfigurationName().get()); project.getExtensions().configure(RunManager.class, runContainer -> runContainer.configureAll(run -> { + run.getDependencies().getRuntime().add(runRuntimeConfiguration); + })); + + final RunManager runManager = project.getExtensions().getByType(RunManager.class); + project.getConfigurations().addRule("Create run specific runtime configuration", configurationName -> { + if (!configurationName.endsWith(configurations.getPerRunRuntimeConfigurationPostFix().get())) + return; + + final String runName = configurationName.substring(0, configurationName.length() - configurations.getPerRunRuntimeConfigurationPostFix().get().length()); + if (runManager.findByName(runName) == null) + return; + + final Run run = runManager.getByName(runName); final Configuration runSpecificRuntimeConfiguration = project.getConfigurations().maybeCreate(ConfigurationUtils.getRunName(run, configurations.getPerRunRuntimeConfigurationPostFix().get())); - run.getDependencies().getRuntime().add(runRuntimeConfiguration); run.getDependencies().getRuntime().add(runSpecificRuntimeConfiguration); - })); + }); } private static void configureIDEConventions(Project project, Conventions conventions) { 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 2d14ce9d..23be5b83 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 @@ -5,6 +5,7 @@ import net.minecraftforge.gdi.ConfigurableDSLElement; import net.neoforged.gradle.common.extensions.IdeManagementExtension; import net.neoforged.gradle.common.tasks.ArtifactFromOutput; +import net.neoforged.gradle.common.util.ConfigurationUtils; import net.neoforged.gradle.dsl.common.extensions.dependency.replacement.DependencyReplacement; import net.neoforged.gradle.dsl.common.extensions.dependency.replacement.DependencyReplacementHandler; import net.neoforged.gradle.dsl.common.extensions.dependency.replacement.ReplacementAware; @@ -13,7 +14,6 @@ import net.neoforged.gradle.dsl.common.extensions.repository.Repository; import net.neoforged.gradle.dsl.common.tasks.WithOutput; import net.neoforged.gradle.dsl.common.util.CommonRuntimeUtils; -import net.neoforged.gradle.common.util.ConfigurationUtils; import org.gradle.api.GradleException; import org.gradle.api.NamedDomainObjectContainer; import org.gradle.api.Project; @@ -27,6 +27,7 @@ import javax.inject.Inject; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; /** * Defines the implementation of the @{link DependencyReplacement} extension. @@ -39,7 +40,7 @@ public abstract class ReplacementLogic implements ConfigurableDSLElement> dependencyReplacementInformation = HashBasedTable.create(); private final Table repositoryEntries = HashBasedTable.create(); - private final Table originalDependencyLookup = HashBasedTable.create(); + private final Map originalDependencyLookup = new ConcurrentHashMap<>(); private final NamedDomainObjectContainer dependencyReplacementHandlers; private final List whenDependencyReplaced = new ArrayList<>(); @@ -59,9 +60,7 @@ public ReplacementLogic(Project project) { public void whenDependencyReplaced(DependencyReplacedCallback dependencyAction) { this.whenDependencyReplaced.add(dependencyAction); - for (Table.Cell dependencyConfigurationDependencyCell : this.originalDependencyLookup.cellSet()) { - dependencyAction.apply(dependencyConfigurationDependencyCell.getRowKey(), dependencyConfigurationDependencyCell.getColumnKey(), dependencyConfigurationDependencyCell.getValue()); - } + this.originalDependencyLookup.forEach(dependencyAction::apply); } @Override @@ -113,18 +112,9 @@ public NamedDomainObjectContainer getReplacementHa @NotNull @Override - public Dependency optionallyConvertBackToOriginal(@NotNull final Dependency dependency, Configuration configuration) { - final Dependency originalDependency = originalDependencyLookup.get(dependency, configuration); - if (originalDependency == null && !configuration.getExtendsFrom().isEmpty()) { - //Check if we have a parent configuration that might have the original dependency. - for (Configuration parentConfiguration : configuration.getExtendsFrom()) { - return optionallyConvertBackToOriginal(dependency, parentConfiguration); - } - } else if (originalDependency != null) { - return originalDependency; - } - - return dependency; + public Dependency optionallyConvertBackToOriginal(@NotNull final Dependency dependency) { + final Dependency originalDependency = originalDependencyLookup.get(dependency); + return Objects.requireNonNullElse(originalDependency, dependency); } /** @@ -273,36 +263,34 @@ private void handleDependencyReplacement(Configuration configuration, Dependency //Find the configurations that the dependency should be replaced in. final List targetConfigurations = ConfigurationUtils.findReplacementConfigurations(project, configuration); + //Create a dependency from the tasks that copies the raw jar to the repository. + //The sources jar is not needed here. + final ConfigurableFileCollection replacedFiles = createDependencyFromTask(rawTask); + final Dependency replacedDependency = project.getDependencies().create(replacedFiles); + final Dependency localRepoDependency = newRepoEntry.getDependency(); + //For each configuration that we target we now need to add the new dependencies to. for (Configuration targetConfiguration : targetConfigurations) { try { - //Create a dependency from the tasks that copies the raw jar to the repository. - //The sources jar is not needed here. - final Provider replacedFiles = createDependencyFromTask(rawTask); - //Add the new dependency to the target configuration. final DependencySet targetDependencies = targetConfiguration == configuration ? configuredSet : targetConfiguration.getDependencies(); - final Provider replacedDependencies = replacedFiles - .map(files -> project.getDependencies().create(files)); - final Provider newRepoDependency = project.provider(newRepoEntry::getDependency); - //Add the new dependency to the target configuration. - targetDependencies.addLater(replacedDependencies); - targetDependencies.addLater(newRepoDependency); - - //Keep track of the original dependency, so we can convert back if needed. - originalDependencyLookup.put(newRepoEntry.getDependency(), targetConfiguration, dependency); - - for (DependencyReplacedCallback dependencyReplacedCallback : this.whenDependencyReplaced) { - dependencyReplacedCallback.apply(newRepoEntry.getDependency(), targetConfiguration, dependency); - } + targetDependencies.add(replacedDependency); + targetDependencies.add(localRepoDependency); } catch (Exception exception) { throw new GradleException("Failed to add the replaced dependency to the configuration " + targetConfiguration.getName() + ": " + exception.getMessage(), exception); } } + + //Keep track of the original dependency, so we can convert back if needed. + originalDependencyLookup.put(localRepoDependency, dependency); + + for (DependencyReplacedCallback dependencyReplacedCallback : this.whenDependencyReplaced) { + dependencyReplacedCallback.apply(localRepoDependency, dependency); + } } /** @@ -475,7 +463,7 @@ Entry createDummyDependency(final Dependency dependency, final ReplacementResult return entry; } - public Provider createDependencyFromTask(TaskProvider task) { - return task.map(taskWithOutput -> project.files(taskWithOutput.getOutput())); + public ConfigurableFileCollection createDependencyFromTask(TaskProvider task) { + return project.files(task.flatMap(WithOutput::getOutput)); } } diff --git a/common/src/main/java/net/neoforged/gradle/common/runs/run/RunImpl.java b/common/src/main/java/net/neoforged/gradle/common/runs/run/RunImpl.java index f2c88db2..c542ce32 100644 --- a/common/src/main/java/net/neoforged/gradle/common/runs/run/RunImpl.java +++ b/common/src/main/java/net/neoforged/gradle/common/runs/run/RunImpl.java @@ -483,7 +483,7 @@ private void configureFromSDKs() { }); final DependencyReplacement replacementLogic = project.getExtensions().getByType(DependencyReplacement.class); - replacementLogic.whenDependencyReplaced((virtualDependency, targetConfiguration, originalDependency) -> { + replacementLogic.whenDependencyReplaced((virtualDependency, originalDependency) -> { if (unconfiguredSourceSets.isEmpty()) { return; } diff --git a/common/src/main/java/net/neoforged/gradle/common/util/ConfigurationUtils.java b/common/src/main/java/net/neoforged/gradle/common/util/ConfigurationUtils.java index 1bfd2592..14cd9f7d 100644 --- a/common/src/main/java/net/neoforged/gradle/common/util/ConfigurationUtils.java +++ b/common/src/main/java/net/neoforged/gradle/common/util/ConfigurationUtils.java @@ -1,10 +1,8 @@ package net.neoforged.gradle.common.util; import net.neoforged.gradle.dsl.common.extensions.dependency.replacement.DependencyReplacement; -import net.neoforged.gradle.dsl.common.extensions.subsystems.Subsystems; import net.neoforged.gradle.dsl.common.runs.run.Run; import org.apache.commons.lang3.StringUtils; -import org.codehaus.groovy.runtime.DefaultGroovyMethods; import org.codehaus.groovy.runtime.StringGroovyMethods; import org.gradle.api.Action; import org.gradle.api.Project; @@ -17,7 +15,10 @@ import org.gradle.util.internal.GUtil; import java.io.File; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.function.Function; public class ConfigurationUtils { @@ -28,6 +29,21 @@ private ConfigurationUtils() { throw new IllegalStateException("Can not instantiate an instance of: ConfigurationUtils. This is a utility class"); } + /** + * Extends the dependencies and dependency constraints of the target configuration with the dependencies and dependency constraints of the given configurations. + * + * @param project The project to create the configuration for + * @param target The configuration to extend + * @param configurations The configurations to extend from + */ + public static void extendsFrom(final Project project, final Configuration target, final Configuration... configurations) { + for (Configuration configuration : configurations) { + //We treat each configuration as a dependency collector in and of it-self, and copy the dependencies and dependency constraints to the target configuration. + target.getDependencies().addAllLater(project.provider(configuration::getDependencies)); + target.getDependencyConstraints().addAllLater(project.provider(configuration::getDependencyConstraints)); + } + } + /** * Creates a configuration that can be resolved, but not consumed. * @@ -37,18 +53,10 @@ private ConfigurationUtils() { * @return The detached configuration */ public static Configuration temporaryConfiguration(final Project project, final String context, final Dependency... dependencies) { - final Configuration configuration = project.getConfigurations().maybeCreate("neoGradleInternal" + StringGroovyMethods.capitalize(context)); - - if (configuration.getDependencies().isEmpty()) { - DefaultGroovyMethods.addAll(configuration.getDependencies(), dependencies); - - configuration.setCanBeConsumed(false); - configuration.setCanBeResolved(true); - - final DependencyReplacement dependencyReplacement = project.getExtensions().getByType(DependencyReplacement.class); - dependencyReplacement.handleConfiguration(configuration); - } + final Configuration configuration = project.getConfigurations().detachedConfiguration(dependencies); + final DependencyReplacement dependencyReplacement = project.getExtensions().getByType(DependencyReplacement.class); + dependencyReplacement.handleConfiguration(configuration); return configuration; } @@ -62,23 +70,13 @@ public static Configuration temporaryConfiguration(final Project project, final * @return The detached configuration */ public static Configuration temporaryConfiguration(final Project project, final String context, final Action processor) { - final String name = "neoGradleInternal" + StringGroovyMethods.capitalize(context); - final boolean exists = project.getConfigurations().getNames().contains(name); + final Configuration config = project.getConfigurations().detachedConfiguration(); + processor.execute(config); - final Configuration configuration = project.getConfigurations().maybeCreate("neoGradleInternal" + StringGroovyMethods.capitalize(context)); + final DependencyReplacement dependencyReplacement = project.getExtensions().getByType(DependencyReplacement.class); + dependencyReplacement.handleConfiguration(config); - if (!exists) { - processor.execute(configuration); - - configuration.setCanBeConsumed(false); - configuration.setCanBeResolved(true); - - final DependencyReplacement dependencyReplacement = project.getExtensions().getByType(DependencyReplacement.class); - dependencyReplacement.handleConfiguration(configuration); - } - - - return configuration; + return config; } /** @@ -100,17 +98,9 @@ public static boolean isUnhandledConfiguration(Configuration configuration) { * @return The detached configuration */ public static Configuration temporaryUnhandledConfiguration(final ConfigurationContainer configurations, final String context, final Dependency... dependencies) { - final Configuration configuration = configurations.maybeCreate("neoGradleInternalUnhandled" + StringGroovyMethods.capitalize(context)); - UNHANDLED_CONFIGURATIONS.add(configuration); - - if (configuration.getDependencies().isEmpty()) { - configuration.getDependencies().addAll(Arrays.asList(dependencies)); - configuration.setCanBeConsumed(false); - configuration.setCanBeResolved(true); - } - - - return configuration; + final Configuration config = configurations.detachedConfiguration(dependencies); + UNHANDLED_CONFIGURATIONS.add(config); + return config; } /** @@ -122,23 +112,10 @@ public static Configuration temporaryUnhandledConfiguration(final ConfigurationC * @return The detached configuration */ public static Configuration temporaryUnhandledConfiguration(final ConfigurationContainer configurations, final String context, final Provider> dependencies) { - final String name = "neoGradleInternalUnhandled" + StringGroovyMethods.capitalize(context); - if (configurations.findByName(name) != null) { - return configurations.getByName(name); - } - - final Configuration configuration = configurations.create(name); - UNHANDLED_CONFIGURATIONS.add(configuration); - - if (configuration.getDependencies().isEmpty()) { - configuration.getDependencies().addAllLater(dependencies); - - configuration.setCanBeConsumed(false); - configuration.setCanBeResolved(true); - } - - - return configuration; + final Configuration config = configurations.detachedConfiguration(); + config.getDependencies().addAllLater(dependencies); + UNHANDLED_CONFIGURATIONS.add(config); + return config; } /** @@ -150,25 +127,16 @@ public static Configuration temporaryUnhandledConfiguration(final ConfigurationC * @return The detached configuration */ public static Configuration temporaryUnhandledNotTransitiveConfiguration(final ConfigurationContainer configurations, final String context, final Dependency... dependencies) { - final Configuration configuration = configurations.maybeCreate("neoGradleInternalUnhandled" + StringGroovyMethods.capitalize(context)); - UNHANDLED_CONFIGURATIONS.add(configuration); - - if (configuration.getDependencies().isEmpty()) { - DefaultGroovyMethods.addAll(configuration.getDependencies(), dependencies); - - configuration.setCanBeConsumed(false); - configuration.setCanBeResolved(true); - configuration.setTransitive(false); - } - - - return configuration; + final Configuration config = configurations.detachedConfiguration(dependencies); + config.setTransitive(false); + UNHANDLED_CONFIGURATIONS.add(config); + return config; } /** * Creates a provider that will resolve a temporary configuration containing the given dependency. */ - public static Provider getArtifactProvider(Project project, String context, Provider dependencyNotationProvider) { + public static Provider getArtifactProvider(Project project, String context, Provider dependencyNotationProvider) { return dependencyNotationProvider.flatMap(dependencyNotation -> { Configuration configuration = temporaryUnhandledNotTransitiveConfiguration(project.getConfigurations(), context, project.getDependencies().create(dependencyNotation)); return configuration.getElements().map(files -> files.iterator().next().getAsFile()); @@ -186,7 +154,6 @@ public static List findReplacementConfigurations(final Project pr resultContainer.add(configuration); } - return new ArrayList<>(resultContainer); } @@ -237,9 +204,11 @@ public static List findRuntimeOnlyConfigurationFromSourceSetRepla final Set supers = getAllSuperConfigurations(runtimeClasspath); if (supers.contains(runtimeOnly) && supers.contains(configuration)) { - final Configuration reallyRuntimeOnly = project.getConfigurations().maybeCreate(getSourceSetName(sourceSet, "%s%s".formatted(NEOGRADLE_RUNTIME_REPLACEMENT, StringUtils.capitalize(sourceSet.getName())))); - runtimeClasspath.extendsFrom(reallyRuntimeOnly); - targets.add(reallyRuntimeOnly); + final Configuration detachedRuntimeOnly = project.getConfigurations().detachedConfiguration(); + + extendsFrom(project, runtimeClasspath, detachedRuntimeOnly); + + targets.add(detachedRuntimeOnly); } }); @@ -314,6 +283,5 @@ public static String getTaskBaseName(final SourceSet sourceSet) { return sourceSet.getName().equals(SourceSet.MAIN_SOURCE_SET_NAME) ? "" : GUtil.toCamelCase(sourceSet.getName()); } - private static Set UNHANDLED_CONFIGURATIONS = new HashSet(); - + private static final Set UNHANDLED_CONFIGURATIONS = new HashSet(); } diff --git a/common/src/main/java/net/neoforged/gradle/common/util/TaskDependencyUtils.java b/common/src/main/java/net/neoforged/gradle/common/util/TaskDependencyUtils.java index 70430297..588e060f 100644 --- a/common/src/main/java/net/neoforged/gradle/common/util/TaskDependencyUtils.java +++ b/common/src/main/java/net/neoforged/gradle/common/util/TaskDependencyUtils.java @@ -237,7 +237,7 @@ private void processConfiguration(Configuration configuration) { //Grab the original dependencies if we have a replacement extension final DependencyReplacement replacement = project.getExtensions().findByType(DependencyReplacement.class); final Set operatingSet = replacement == null ? dependencies : dependencies.stream() - .map(dependency -> replacement.optionallyConvertBackToOriginal(dependency, configuration)) + .map(replacement::optionallyConvertBackToOriginal) .collect(Collectors.toSet()); this.runtimes.stream() diff --git a/dsl/common/src/main/groovy/net/neoforged/gradle/dsl/common/extensions/dependency/replacement/DependencyReplacement.groovy b/dsl/common/src/main/groovy/net/neoforged/gradle/dsl/common/extensions/dependency/replacement/DependencyReplacement.groovy index 97ed9e00..68f27e6c 100644 --- a/dsl/common/src/main/groovy/net/neoforged/gradle/dsl/common/extensions/dependency/replacement/DependencyReplacement.groovy +++ b/dsl/common/src/main/groovy/net/neoforged/gradle/dsl/common/extensions/dependency/replacement/DependencyReplacement.groovy @@ -3,7 +3,6 @@ package net.neoforged.gradle.dsl.common.extensions.dependency.replacement import groovy.transform.CompileStatic import net.minecraftforge.gdi.BaseDSLElement import net.minecraftforge.gdi.annotations.DSLProperty -import org.gradle.api.Action import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Dependency @@ -34,12 +33,11 @@ interface DependencyReplacement extends BaseDSLElement { /** * Optionally converts the given dependency back to the original dependency it replaced. * - * @param dependency The dependency to optionally convert back. * @param configuration The configuration the given dependency can be found it resides in. * @return The original dependency if it can be converted back, otherwise the given dependency. */ @NotNull - Dependency optionallyConvertBackToOriginal(Dependency dependency, Configuration configuration) + Dependency optionallyConvertBackToOriginal(Dependency dependency) /** * Invoked when a dependency is replaced. @@ -57,9 +55,8 @@ interface DependencyReplacement extends BaseDSLElement { * Invoked when a dependency is replaced. * * @param virtualDependency The virtual dependency. - * @param targetConfiguration The target configuration in which the virtual dependency resides. * @param originalDependency The original dependency. */ - void apply(Dependency virtualDependency, Configuration targetConfiguration, Dependency originalDependency); + void apply(Dependency virtualDependency, Dependency originalDependency); } } diff --git a/examples/multi_neoforge_root/api/build.gradle b/examples/multi_neoforge_root/api/build.gradle new file mode 100644 index 00000000..eaa53924 --- /dev/null +++ b/examples/multi_neoforge_root/api/build.gradle @@ -0,0 +1,16 @@ +plugins { + id 'net.neoforged.gradle.userdev' + id 'java-library' +} + + + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + dependencies { + api(libs.neoforge) + } + \ No newline at end of file diff --git a/examples/multi_neoforge_root/api/gradle.properties b/examples/multi_neoforge_root/api/gradle.properties new file mode 100644 index 00000000..5adc9998 --- /dev/null +++ b/examples/multi_neoforge_root/api/gradle.properties @@ -0,0 +1,3 @@ +net.neoforged.gradle.caching.cacheDirectory=/tmp/spock_multiple_projects_w_0_tempDir7138874024286350570/.ng-cache +org.gradle.console=rich +org.gradle.jvmargs=-Xmx8000m \ No newline at end of file diff --git a/examples/multi_neoforge_root/api/runs/junit/junit_jvm_args.txt b/examples/multi_neoforge_root/api/runs/junit/junit_jvm_args.txt new file mode 100644 index 00000000..c688e6ee --- /dev/null +++ b/examples/multi_neoforge_root/api/runs/junit/junit_jvm_args.txt @@ -0,0 +1,24 @@ +-p +/var/home/marchermans/.gradle/caches/modules-2/files-2.1/cpw.mods/bootstraplauncher/2.0.2/1a2d076cbc33b0520cbacd591224427b2a20047d/bootstraplauncher-2.0.2.jar:/var/home/marchermans/.gradle/caches/modules-2/files-2.1/cpw.mods/securejarhandler/3.0.8/c0ef95cecd8699a0449053ac7d9c160748d902cd/securejarhandler-3.0.8.jar:/var/home/marchermans/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-commons/9.7/e86dda4696d3c185fcc95d8d311904e7ce38a53f/asm-commons-9.7.jar:/var/home/marchermans/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-util/9.7/c0655519f24d92af2202cb681cd7c1569df6ead6/asm-util-9.7.jar:/var/home/marchermans/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-analysis/9.7/e4a258b7eb96107106c0599f0061cfc1832fe07a/asm-analysis-9.7.jar:/var/home/marchermans/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-tree/9.7/e446a17b175bfb733b87c5c2560ccb4e57d69f1a/asm-tree-9.7.jar:/var/home/marchermans/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm/9.7/73d7b3086e14beb604ced229c302feff6449723/asm-9.7.jar:/var/home/marchermans/.gradle/caches/modules-2/files-2.1/net.neoforged/JarJarFileSystems/0.4.1/78f59f89defcd032ed788b151ca6a0d40ace796a/JarJarFileSystems-0.4.1.jar +--add-modules +ALL-MODULE-PATH +--add-opens +java.base/java.util.jar=cpw.mods.securejarhandler +--add-opens +java.base/java.lang.invoke=cpw.mods.securejarhandler +--add-exports +java.base/sun.security.util=cpw.mods.securejarhandler +--add-exports +jdk.naming.dns/com.sun.jndi.dns=java.naming +-p +/var/home/marchermans/.gradle/caches/modules-2/files-2.1/cpw.mods/bootstraplauncher/2.0.2/1a2d076cbc33b0520cbacd591224427b2a20047d/bootstraplauncher-2.0.2.jar:/var/home/marchermans/.gradle/caches/modules-2/files-2.1/cpw.mods/securejarhandler/3.0.8/c0ef95cecd8699a0449053ac7d9c160748d902cd/securejarhandler-3.0.8.jar:/var/home/marchermans/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-commons/9.7/e86dda4696d3c185fcc95d8d311904e7ce38a53f/asm-commons-9.7.jar:/var/home/marchermans/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-util/9.7/c0655519f24d92af2202cb681cd7c1569df6ead6/asm-util-9.7.jar:/var/home/marchermans/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-analysis/9.7/e4a258b7eb96107106c0599f0061cfc1832fe07a/asm-analysis-9.7.jar:/var/home/marchermans/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm-tree/9.7/e446a17b175bfb733b87c5c2560ccb4e57d69f1a/asm-tree-9.7.jar:/var/home/marchermans/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm/9.7/73d7b3086e14beb604ced229c302feff6449723/asm-9.7.jar:/var/home/marchermans/.gradle/caches/modules-2/files-2.1/net.neoforged/JarJarFileSystems/0.4.1/78f59f89defcd032ed788b151ca6a0d40ace796a/JarJarFileSystems-0.4.1.jar +--add-modules +ALL-MODULE-PATH +--add-opens +java.base/java.util.jar=cpw.mods.securejarhandler +--add-opens +java.base/java.lang.invoke=cpw.mods.securejarhandler +--add-exports +java.base/sun.security.util=cpw.mods.securejarhandler +--add-exports +jdk.naming.dns/com.sun.jndi.dns=java.naming diff --git a/examples/multi_neoforge_root/api/runs/junit/junit_test_args.txt b/examples/multi_neoforge_root/api/runs/junit/junit_test_args.txt new file mode 100644 index 00000000..b38c35c7 --- /dev/null +++ b/examples/multi_neoforge_root/api/runs/junit/junit_test_args.txt @@ -0,0 +1,36 @@ +--launchTarget +forgejunituserdev +--version +21.3.6-beta +--assetIndex +asset-index +--assetsDir +/var/home/marchermans/.gradle/caches/minecraft/assets +--gameDir +. +--fml.neoForgeVersion +21.3.6-beta +--fml.fmlVersion +4.0.31 +--fml.mcVersion +1.21.3 +--fml.neoFormVersion +20241023.131943 +--launchTarget +forgejunituserdev +--version +21.3.6-beta +--assetIndex +asset-index +--assetsDir +/var/home/marchermans/.gradle/caches/minecraft/assets +--gameDir +. +--fml.neoForgeVersion +21.3.6-beta +--fml.fmlVersion +4.0.31 +--fml.mcVersion +1.21.3 +--fml.neoFormVersion +20241023.131943 diff --git a/examples/multi_neoforge_root/api/src/main/java/net/neoforged/gradle/apitest/FunctionalTests.java b/examples/multi_neoforge_root/api/src/main/java/net/neoforged/gradle/apitest/FunctionalTests.java new file mode 100644 index 00000000..8a21ee20 --- /dev/null +++ b/examples/multi_neoforge_root/api/src/main/java/net/neoforged/gradle/apitest/FunctionalTests.java @@ -0,0 +1,11 @@ + + package net.neoforged.gradle.apitest; + + import net.minecraft.client.Minecraft; + + public class FunctionalTests { + public static void main(String[] args) { + System.out.println(Minecraft.getInstance().getClass().toString()); + } + } + \ No newline at end of file diff --git a/examples/multi_neoforge_root/build.gradle b/examples/multi_neoforge_root/build.gradle new file mode 100644 index 00000000..939da398 --- /dev/null +++ b/examples/multi_neoforge_root/build.gradle @@ -0,0 +1,11 @@ +plugins { + id 'net.neoforged.gradle.userdev' +} + + + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + \ No newline at end of file diff --git a/examples/multi_neoforge_root/gradle.properties b/examples/multi_neoforge_root/gradle.properties new file mode 100644 index 00000000..5adc9998 --- /dev/null +++ b/examples/multi_neoforge_root/gradle.properties @@ -0,0 +1,3 @@ +net.neoforged.gradle.caching.cacheDirectory=/tmp/spock_multiple_projects_w_0_tempDir7138874024286350570/.ng-cache +org.gradle.console=rich +org.gradle.jvmargs=-Xmx8000m \ No newline at end of file diff --git a/examples/multi_neoforge_root/gradle/libs.versions.toml b/examples/multi_neoforge_root/gradle/libs.versions.toml new file mode 100644 index 00000000..33692833 --- /dev/null +++ b/examples/multi_neoforge_root/gradle/libs.versions.toml @@ -0,0 +1,6 @@ +[versions] + # Neoforge Settings + neoforge = "+" + + [libraries] + neoforge = { group = "net.neoforged", name = "neoforge", version.ref = "neoforge" } \ No newline at end of file diff --git a/examples/multi_neoforge_root/gradle/wrapper/gradle-wrapper.jar b/examples/multi_neoforge_root/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..e6441136 Binary files /dev/null and b/examples/multi_neoforge_root/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/multi_neoforge_root/gradle/wrapper/gradle-wrapper.properties b/examples/multi_neoforge_root/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..66cd5a0e --- /dev/null +++ b/examples/multi_neoforge_root/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-all.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/multi_neoforge_root/main/build.gradle b/examples/multi_neoforge_root/main/build.gradle new file mode 100644 index 00000000..82b8061b --- /dev/null +++ b/examples/multi_neoforge_root/main/build.gradle @@ -0,0 +1,15 @@ +plugins { + id 'net.neoforged.gradle.userdev' +} + + + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + dependencies { + implementation project(':api') + } + \ No newline at end of file diff --git a/examples/multi_neoforge_root/main/gradle.properties b/examples/multi_neoforge_root/main/gradle.properties new file mode 100644 index 00000000..5adc9998 --- /dev/null +++ b/examples/multi_neoforge_root/main/gradle.properties @@ -0,0 +1,3 @@ +net.neoforged.gradle.caching.cacheDirectory=/tmp/spock_multiple_projects_w_0_tempDir7138874024286350570/.ng-cache +org.gradle.console=rich +org.gradle.jvmargs=-Xmx8000m \ No newline at end of file diff --git a/examples/multi_neoforge_root/main/src/main/java/net/neoforged/gradle/main/ApiTests.java b/examples/multi_neoforge_root/main/src/main/java/net/neoforged/gradle/main/ApiTests.java new file mode 100644 index 00000000..d7852120 --- /dev/null +++ b/examples/multi_neoforge_root/main/src/main/java/net/neoforged/gradle/main/ApiTests.java @@ -0,0 +1,13 @@ + + package net.neoforged.gradle.main; + + import net.minecraft.client.Minecraft; + import net.neoforged.gradle.apitest.FunctionalTests; + + public class ApiTests { + public static void main(String[] args) { + System.out.println(Minecraft.getInstance().getClass().toString()); + FunctionalTests.main(args); + } + } + \ No newline at end of file diff --git a/examples/multi_neoforge_root/settings.gradle b/examples/multi_neoforge_root/settings.gradle new file mode 100644 index 00000000..92bbc41c --- /dev/null +++ b/examples/multi_neoforge_root/settings.gradle @@ -0,0 +1,18 @@ +pluginManagement { + repositories { + gradlePluginPortal() + mavenLocal() + maven { url = 'https://maven.neoforged.net/' } + } + + includeBuild '../../' +} + +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' +} + +rootProject.name = 'multi_neoforge_root' + +include 'api' +include 'main' diff --git a/examples/runs/build.gradle b/examples/runs/build.gradle index 59e95bbe..a3285d87 100644 --- a/examples/runs/build.gradle +++ b/examples/runs/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'net.neoforged.gradle.userdev' +// id 'net.neoforged.gradle.userdev' } java { @@ -9,11 +9,13 @@ java { } dependencies { - implementation 'net.neoforged:neoforge:+' + //implementation 'net.neoforged:neoforge:+' } +/* runs { client { // no modsource } -} \ No newline at end of file +} +*/ diff --git a/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/extensions/NeoFormRuntimeExtension.java b/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/extensions/NeoFormRuntimeExtension.java index 7fce0fe7..14e035f6 100644 --- a/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/extensions/NeoFormRuntimeExtension.java +++ b/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/extensions/NeoFormRuntimeExtension.java @@ -43,6 +43,7 @@ import org.gradle.api.tasks.compile.AbstractCompile; import org.gradle.api.tasks.compile.ForkOptions; import org.gradle.jvm.toolchain.JavaLanguageVersion; +import org.gradle.process.CommandLineArgumentProvider; import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; @@ -455,7 +456,13 @@ protected void bakeDefinition(NeoFormRuntimeDefinition definition) { ForkOptions forkOptions = task.getOptions().getForkOptions(); forkOptions.setMemoryMaximumSize(maxMemory); forkOptions.setJvmArgs(settings.getJvmArgs().get()); - task.getOptions().getCompilerArgumentProviders().add(settings.getArgs()::get); + //noinspection Convert2Lambda -> May not be a lambda as this causes issues: In plugin 'net.neoforged.gradle.neoform.NeoFormProjectPlugin' property 'options.compilerArgumentProviders.$0' was implemented by the Java lambda 'net.neoforged.gradle.neoform.runtime.extensions.NeoFormRuntimeExtension$$Lambda$2667/0x000000010105ab98'. + task.getOptions().getCompilerArgumentProviders().add(new CommandLineArgumentProvider() { + @Override + public Iterable asArguments() { + return settings.getArgs().get(); + } + }); task.getJavaVersion().set( definition.getVersionJson() 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 8f33dc9c..99342f1e 100644 --- a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/FunctionalTests.groovy +++ b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/FunctionalTests.groovy @@ -407,4 +407,78 @@ class FunctionalTests extends BuilderBasedTestSpecification { run.task(':clean').outcome == TaskOutcome.SUCCESS run.task(':build').outcome == TaskOutcome.SUCCESS } + + def "a mod with userdev does not expose the userdev artifact to consumers"() { + given: + def project = create("gradle_multi_sourceset", { + it.build(""" + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + dependencies { + api 'net.neoforged:neoforge:+' + } + + publishing { + repositories { + maven { + // change to point to your repo, e.g. http://my.org/repo + url = layout.buildDirectory.dir('repo') + } + } + + publications { + maven(MavenPublication) { + groupId = 'org.gradle.sample' + artifactId = 'library' + version = '1.1' + + from components.java + } + } + } + + """) + 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() + it.withGlobalCacheDirectory(tempDir) + it.plugin("java-library") + it.plugin("maven-publish") + }) + + when: + def run = project.run { + it.tasks('clean', 'build', 'publish') + it.stacktrace() + } + + then: + run.task(':clean').outcome == TaskOutcome.SUCCESS + run.task(':build').outcome == TaskOutcome.SUCCESS + run.task(':publish').outcome == TaskOutcome.SUCCESS + + and: + def repo = run.file("build/repo/org/gradle/sample/library/1.1") + def moduleFile = new File(repo, "library-1.1.module") + def pomFile = new File(repo, "library-1.1.pom") + + then: + moduleFile.exists() + pomFile.exists() + !moduleFile.text.contains("neoforged") + !pomFile.text.contains("neoforged") + } } diff --git a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/MultiProjectTests.groovy b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/MultiProjectTests.groovy index bcf06bc1..9f42ddb4 100644 --- a/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/MultiProjectTests.groovy +++ b/userdev/src/functionalTest/groovy/net/neoforged/gradle/userdev/MultiProjectTests.groovy @@ -105,6 +105,102 @@ class MultiProjectTests extends BuilderBasedTestSpecification { run.output.contains("Caused by: net.neoforged.fml.ModLoadingException: Loading errors encountered:") } + def "multiple projects with neoforge dependencies from version catalogs should be able to build"() { + given: + def rootProject = create("multi_neoforge_root", { + it.file("gradle/libs.versions.toml", + """ + [versions] + # Neoforge Settings + neoforge = "+" + + [libraries] + neoforge = { group = "net.neoforged", name = "neoforge", version.ref = "neoforge" } + """.trim()) + + it.build(""" + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + """) + it.withToolchains() + it.withGlobalCacheDirectory(tempDir) + }) + + def apiProject = create(rootProject, "api", { + it.build(""" + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + dependencies { + api(libs.neoforge) + } + """) + it.file("src/main/java/net/neoforged/gradle/apitest/FunctionalTests.java", """ + package net.neoforged.gradle.apitest; + + import net.minecraft.client.Minecraft; + + public class FunctionalTests { + public static void main(String[] args) { + System.out.println(Minecraft.getInstance().getClass().toString()); + } + } + """) + it.withToolchains() + it.withGlobalCacheDirectory(tempDir) + it.plugin(this.pluginUnderTest) + it.plugin("java-library") + }) + + def mainProject = create(rootProject,"main", { + it.build(""" + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + dependencies { + implementation project(':api') + //We still need a neoforge dependency here, because neoforge is not exposed from the api project. Compile would faile. + implementation libs.neoforge + } + """) + it.file("src/main/java/net/neoforged/gradle/main/ApiTests.java", """ + package net.neoforged.gradle.main; + + import net.minecraft.client.Minecraft; + import net.neoforged.gradle.apitest.FunctionalTests; + + public class ApiTests { + public static void main(String[] args) { + System.out.println(Minecraft.getInstance().getClass().toString()); + FunctionalTests.main(args); + } + } + """) + it.withToolchains() + it.withGlobalCacheDirectory(tempDir) + it.plugin(this.pluginUnderTest) + }) + + when: + def run = rootProject.run { + it.tasks(':main:build') + it.stacktrace() + it.debug() + } + + then: + run.task(':main:build').outcome == TaskOutcome.SUCCESS + } + def "multiple projects with neoforge dependencies should be able to run the game when renderDoc is enabled"() { given: def rootProject = create("multi_neoforge_root_renderdoc", { 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 2acf60c3..aa3fe835 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 @@ -85,8 +85,8 @@ private void registerReplacementHandler(Project project) { "NeoForgeUserDevAdditionalReplacementDependenciesFor" + runtimeDefinition.getSpecification().getIdentifier(), configuration -> { configuration.setDescription("Additional dependencies for the NeoForge UserDev replacement for " + runtimeDefinition.getSpecification().getIdentifier()); - configuration.extendsFrom(runtimeDefinition.getNeoFormRuntimeDefinition().getMinecraftDependenciesConfiguration()); - configuration.extendsFrom(runtimeDefinition.getAdditionalUserDevDependencies()); + ConfigurationUtils.extendsFrom(project, configuration, runtimeDefinition.getNeoFormRuntimeDefinition().getMinecraftDependenciesConfiguration()); + ConfigurationUtils.extendsFrom(project, configuration, runtimeDefinition.getAdditionalUserDevDependencies()); } ); diff --git a/userdev/src/main/java/net/neoforged/gradle/userdev/runtime/definition/UserDevRuntimeDefinition.java b/userdev/src/main/java/net/neoforged/gradle/userdev/runtime/definition/UserDevRuntimeDefinition.java index f0e74743..629fa672 100644 --- a/userdev/src/main/java/net/neoforged/gradle/userdev/runtime/definition/UserDevRuntimeDefinition.java +++ b/userdev/src/main/java/net/neoforged/gradle/userdev/runtime/definition/UserDevRuntimeDefinition.java @@ -137,9 +137,9 @@ protected void buildRunInterpolationData(RunImpl run, @NotNull MapProperty