Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/multi project leaking #167

Merged
merged 8 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.TaskProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.VisibleForTesting;

import javax.inject.Inject;
Expand Down Expand Up @@ -128,7 +127,7 @@ void handleDependency(final Configuration configuration, final ModuleDependency
dependencyReplacementInformation.put(dependency, configuration, candidate);
} else if (dependencyReplacementInformation.contains(dependency, configuration)) {
candidate = dependencyReplacementInformation.get(dependency, configuration);
if (candidate == null) {
if (candidate == null || !candidate.isPresent()) {
candidate = Optional.empty();
dependencyReplacementInformation.remove(dependency, configuration);
}
Expand Down Expand Up @@ -236,7 +235,7 @@ void createDependencyReplacementResult(final List<Configuration> configurations,
builder -> configureRepositoryReference(result, externalModuleDependency, builder),
reference -> processRepositoryReference(configurations, result, reference),
builder -> configureRepositoryEntry(result, externalModuleDependency, builder),
entry -> processRepositoryEntry(originalConfiguration, result, generator, repoBaseDir, entry),
entry -> processRepositoryEntry(configurations, result, generator, repoBaseDir, entry),
result.getProcessImmediately()
);
} catch (XMLStreamException | IOException e) {
Expand All @@ -256,7 +255,7 @@ private void processRepositoryReference(List<Configuration> configurations, Depe
}


private void processRepositoryEntry(Configuration originalConfiguration, DependencyReplacementResult result, TaskProviderGenerator generator, Provider<Directory> repoBaseDir, RepositoryEntry<?, ?> entry) {
private void processRepositoryEntry(List<Configuration> originalConfiguration, DependencyReplacementResult result, TaskProviderGenerator generator, Provider<Directory> repoBaseDir, RepositoryEntry<?, ?> entry) {
final ModuleReference reference = entry.toModuleReference();
if (configuredReferences.contains(reference))
return;
Expand All @@ -265,7 +264,7 @@ private void processRepositoryEntry(Configuration originalConfiguration, Depende

final RepositoryEntryGenerationTasks entryGenerationTasks = generator.generate(repoBaseDir, entry);
final Dependency replacedDependency = this.dependencyCreator.from(entryGenerationTasks.rawJarProvider);
originalConfiguration.getDependencies().add(replacedDependency);
originalConfiguration.forEach(config -> config.getDependencies().add(replacedDependency));
result.getOnRepoWritingTaskRegisteredCallback().accept(entryGenerationTasks.rawJarProvider);

afterDefinitionBake(projectAfterBake -> {
Expand Down Expand Up @@ -304,7 +303,7 @@ public void afterDefinitionBake(final Consumer<Project> callback) {
this.afterDefinitionBakeCallbacks.add(callback);
}

private static class RepositoryEntryGenerationTasks {
static class RepositoryEntryGenerationTasks {
private final TaskProvider<? extends WithOutput> rawJarProvider;
private final TaskProvider<? extends WithOutput> sourceJarProvider;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package net.neoforged.gradle.common.util;

import net.neoforged.gradle.dsl.common.util.ConfigurationUtils;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.plugins.ExtensionContainer;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import java.util.*;
import java.util.function.Consumer;

import static org.mockito.Mockito.*;

public class ConfigurationUtilsTest {

@Test
public void findCompileClasspathSourceSetHandlesImplementationAndCompileClasspath() {
final Configuration compileClasspath = mock(Configuration.class);
final Configuration compileOnly = mock(Configuration.class);
final Configuration implementation = mock(Configuration.class);

final ConfigurationContainer configurations = mock(ConfigurationContainer.class);
final Project project = mock(Project.class);
final ExtensionContainer extensions = mock(ExtensionContainer.class);

final SourceSetContainer sourceSets = mock(SourceSetContainer.class);
final SourceSet mainSourceSet = mock(SourceSet.class);

when(configurations.findByName("compileOnly")).thenReturn(compileOnly);
when(configurations.findByName("compileClasspath")).thenReturn(compileClasspath);
when(configurations.findByName("implementation")).thenReturn(implementation);

when(project.getConfigurations()).thenReturn(configurations);

when(project.getExtensions()).thenReturn(extensions);
when(extensions.getByType(SourceSetContainer.class)).thenReturn(sourceSets);

when(sourceSets.getByName("main")).thenReturn(mainSourceSet);
when(mainSourceSet.getCompileClasspathConfigurationName()).thenReturn("compileClasspath");
when(mainSourceSet.getImplementationConfigurationName()).thenReturn("implementation");
when(mainSourceSet.getCompileOnlyConfigurationName()).thenReturn("compileOnly");
doAnswer(invocationOnMock -> {
final Consumer<SourceSet> argument = invocationOnMock.getArgument(0);
argument.accept(mainSourceSet);
return null;
}).when(sourceSets).forEach(ArgumentMatchers.any());

when(compileOnly.getName()).thenReturn("compileOnly");
when(compileClasspath.getName()).thenReturn("compileClasspath");
when(implementation.getName()).thenReturn("implementation");

when(compileClasspath.getExtendsFrom()).thenReturn(buildConfigurationSet(implementation, compileOnly));

final List<Configuration> result = ConfigurationUtils.findCompileOnlyConfigurationForSourceSetReplacement(project, implementation);

Assertions.assertEquals(buildConfigurationList(compileOnly), result);
}

@Test
public void findRuntimeClasspathSourceSetHandlesImplementationAndRuntimeClasspath() {
final Configuration runtimeClasspath = mock(Configuration.class);
final Configuration implementation = mock(Configuration.class);

final ConfigurationContainer configurations = mock(ConfigurationContainer.class);
final Project project = mock(Project.class);
final ExtensionContainer extensions = mock(ExtensionContainer.class);

final SourceSetContainer sourceSets = mock(SourceSetContainer.class);
final SourceSet mainSourceSet = mock(SourceSet.class);

when(configurations.findByName("runtimeClasspath")).thenReturn(runtimeClasspath);
when(configurations.findByName("implementation")).thenReturn(implementation);

final List<Configuration> newConfigurations = new ArrayList<>();
when(configurations.maybeCreate(any())).thenAnswer((Answer<Configuration>) invocationOnMock -> {
final String name = invocationOnMock.getArgument(0);
final Configuration configuration = mock(Configuration.class);
when(configuration.getName()).thenReturn(name);

newConfigurations.add(configuration);

return configuration;
});

when(project.getConfigurations()).thenReturn(configurations);

when(project.getExtensions()).thenReturn(extensions);
when(extensions.getByType(SourceSetContainer.class)).thenReturn(sourceSets);

when(sourceSets.getByName("main")).thenReturn(mainSourceSet);
when(mainSourceSet.getRuntimeClasspathConfigurationName()).thenReturn("runtimeClasspath");
when(mainSourceSet.getImplementationConfigurationName()).thenReturn("implementation");

doAnswer(invocationOnMock -> {
final Consumer<SourceSet> argument = invocationOnMock.getArgument(0);
argument.accept(mainSourceSet);
return null;
}).when(sourceSets).forEach(ArgumentMatchers.any());

when(runtimeClasspath.getName()).thenReturn("runtimeClasspath");
when(implementation.getName()).thenReturn("implementation");

when(runtimeClasspath.getExtendsFrom()).thenReturn(buildConfigurationSet(implementation));

final List<Configuration> result = ConfigurationUtils.findRuntimeOnlyConfigurationFromSourceSetReplacement(project, implementation);

Assertions.assertEquals(newConfigurations, result);
}

@Test
public void getAllExtendingConfigurationOneDeepOnSuperLookup() {
final Configuration source = mock(Configuration.class);
final Configuration target = mock(Configuration.class);

when(source.getExtendsFrom()).thenReturn(buildConfigurationSet(target));

final Set<Configuration> configurations = ConfigurationUtils.getAllSuperConfigurations(source);

Assertions.assertEquals(buildConfigurationSet(target), configurations);
}

@Test
public void getAllExtendingConfigurationRecursiveOnSuperLookup() {
final Configuration source = mock(Configuration.class);
final Configuration levelOne = mock(Configuration.class);
final Configuration levelTwo = mock(Configuration.class);

when(source.getExtendsFrom()).thenReturn(buildConfigurationSet(levelOne));
when(levelOne.getExtendsFrom()).thenReturn(buildConfigurationSet(levelTwo));

final Set<Configuration> configurations = ConfigurationUtils.getAllSuperConfigurations(source);

Assertions.assertEquals(buildConfigurationSet(levelOne, levelTwo), configurations);
}

private Set<Configuration> buildConfigurationSet(Configuration... configurations) {
final Set<Configuration> configurationSet = new HashSet<>();
Collections.addAll(configurationSet, configurations);
return configurationSet;
}

private List<Configuration> buildConfigurationList(Configuration... configurations) {
final List<Configuration> configurationSet = new ArrayList<>();
Collections.addAll(configurationSet, configurations);
return configurationSet;
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package net.neoforged.gradle.common.util;

import net.neoforged.gradle.dsl.common.util.NamingConstants;
import org.junit.Test;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.Map;
Expand All @@ -10,6 +10,7 @@
import static org.junit.jupiter.api.Assertions.assertThrows;

public class MappingUtilsTest {

@Test
public void mappingVersionIsFoundInMappingVersionData() {
final Map<String, String> mappingVersionData = new HashMap<>();
Expand Down
4 changes: 3 additions & 1 deletion dsl/common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ plugins {
}

dependencies {
api "org.codehaus.groovy:groovy-all:${project.groovy_version}"
api ("org.codehaus.groovy:groovy-all:${project.groovy_version}", {
exclude group: 'junit'
})
api "commons-io:commons-io:${project.commons_io_version}"
api "org.apache.maven:maven-artifact:${project.maven_artifact_version}"
api "com.google.guava:guava:${project.guava_version}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ConfigurationContainer
import org.gradle.api.artifacts.Dependency
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.SourceSetContainer
Expand Down Expand Up @@ -71,54 +70,62 @@ class ConfigurationUtils {
static List<Configuration> findReplacementConfigurations(final Project project, final Configuration configuration) {
final Set<Configuration> resultContainer = new HashSet<>();

resultContainer.addAll(findCompileClasspathSourceSet(project, configuration))
resultContainer.addAll(findRuntimeClasspathSourceSet(project, configuration))
resultContainer.addAll(findCompileOnlyConfigurationForSourceSetReplacement(project, configuration))
resultContainer.addAll(findRuntimeOnlyConfigurationFromSourceSetReplacement(project, configuration))

return resultContainer.toList()
}

static List<Configuration> findCompileClasspathSourceSet(final Project project, final Configuration configuration) {
static List<Configuration> findCompileOnlyConfigurationForSourceSetReplacement(final Project project, final Configuration configuration) {
final SourceSetContainer sourceSetContainer = project.getExtensions().getByType(SourceSetContainer.class)
final List<Configuration> targets = new ArrayList<>();

sourceSetContainer.forEach {sourceSet -> {
final Configuration sourceSetConfiguration = project.getConfigurations().findByName(sourceSet.getCompileClasspathConfigurationName())
if (sourceSetConfiguration == null)
final Configuration compileOnly = project.getConfigurations().findByName(sourceSet.getCompileOnlyConfigurationName())
final Configuration compileClasspath = project.getConfigurations().findByName(sourceSet.getCompileClasspathConfigurationName());
if (compileOnly == null)
return;

if (configuration == sourceSetConfiguration) {
if (configuration == compileOnly) {
targets.clear()
targets.add(sourceSetConfiguration)
targets.add(compileOnly)
return targets
}

final Set<Configuration> supers = getAllSuperConfigurations(sourceSetConfiguration)
if (supers.contains(configuration)) {
targets.add(sourceSetConfiguration)
final Set<Configuration> supers = getAllSuperConfigurations(compileClasspath)
if (supers.contains(compileOnly) && supers.contains(configuration)) {
targets.add(compileOnly)
}
}}

return targets
}

static List<Configuration> findRuntimeClasspathSourceSet(final Project project, final Configuration configuration) {
static List<Configuration> findRuntimeOnlyConfigurationFromSourceSetReplacement(final Project project, final Configuration configuration) {
final SourceSetContainer sourceSetContainer = project.getExtensions().getByType(SourceSetContainer.class)
final List<Configuration> targets = new ArrayList<>();

sourceSetContainer.forEach {sourceSet -> {
final Configuration sourceSetConfiguration = project.getConfigurations().findByName(sourceSet.getRuntimeClasspathConfigurationName())
if (sourceSetConfiguration == null)
final Configuration runtimeOnly = project.getConfigurations().findByName(sourceSet.getRuntimeOnlyConfigurationName())
final Configuration runtimeClasspath = project.getConfigurations().findByName(sourceSet.getRuntimeClasspathConfigurationName());
if (runtimeOnly == null)
return;

if (configuration == sourceSetConfiguration) {
if (configuration == runtimeOnly) {
targets.clear()
targets.add(sourceSetConfiguration)
targets.add(runtimeOnly)
return targets
}

final Set<Configuration> supers = getAllSuperConfigurations(sourceSetConfiguration)
if (supers.contains(configuration)) {
targets.add(sourceSetConfiguration)
final Set<Configuration> supers = getAllSuperConfigurations(runtimeClasspath)
if (supers.contains(runtimeOnly) && supers.contains(configuration)) {
//Runtime is a special bunny, we need to make our own configuration in this state to handle it.
//TODO: Once we add the conventions subsystem use its standardized approach.
final Configuration reallyRuntimeOnly = project.getConfigurations().maybeCreate(
getSourceSetName(sourceSet, "runtimeNotPublished")
)
runtimeClasspath.extendsFrom(reallyRuntimeOnly)
targets.add(reallyRuntimeOnly)
}
}}

Expand All @@ -141,4 +148,18 @@ class ConfigurationUtils {
}
}}
}

/**
* Gets the name of the source set with the given post fix
*
* @param sourceSet The source set to get the name of
* @param postFix The post fix to append to the source set name
* @return The name of the source set with the post fix
*/
private static String getSourceSetName(SourceSet sourceSet, String postFix) {
final String capitalized = postFix.capitalize()
final String name = sourceSet.getName() == SourceSet.MAIN_SOURCE_SET_NAME ? "" : sourceSet.getName().capitalize()

return (name + capitalized).uncapitalize()
}
}
4 changes: 3 additions & 1 deletion dsl/mixin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ plugins {
}

dependencies {
api "org.codehaus.groovy:groovy-all:${project.groovy_version}"
api("org.codehaus.groovy:groovy-all:${project.groovy_version}", {
exclude group: 'junit'
})
api "com.google.code.gson:gson:${project.gson_version}"
api "net.neoforged:groovydslimprover:${project.groovy_dsl_improver_version}"
}
4 changes: 3 additions & 1 deletion dsl/neoform/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ dependencies {
api project(':dsl-common')
api project(':utils')

api "org.codehaus.groovy:groovy-all:${project.groovy_version}"
api("org.codehaus.groovy:groovy-all:${project.groovy_version}", {
exclude group: 'junit'
})
api "com.google.code.gson:gson:${project.gson_version}"
api "net.neoforged:groovydslimprover:${project.groovy_dsl_improver_version}"
}
4 changes: 3 additions & 1 deletion dsl/platform/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ plugins {
}

dependencies {
api "org.codehaus.groovy:groovy-all:${project.groovy_version}"
api("org.codehaus.groovy:groovy-all:${project.groovy_version}", {
exclude group: 'junit'
})
api "com.google.code.gson:gson:${project.gson_version}"
api "net.neoforged:groovydslimprover:${project.groovy_dsl_improver_version}"

Expand Down
4 changes: 3 additions & 1 deletion dsl/userdev/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ plugins {
}

dependencies {
api "org.codehaus.groovy:groovy-all:${project.groovy_version}"
api("org.codehaus.groovy:groovy-all:${project.groovy_version}", {
exclude group: 'junit'
})
api "com.google.code.gson:gson:${project.gson_version}"
api "net.neoforged:groovydslimprover:${project.groovy_dsl_improver_version}"

Expand Down
Loading
Loading