Major steps towards config caching support :)

This commit is contained in:
modmuss50
2022-10-06 21:42:45 +01:00
parent 24b727c84c
commit cc43cfc1dc
25 changed files with 295 additions and 181 deletions

View File

@@ -45,7 +45,7 @@ import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.configuration.ide.idea.IdeaUtils;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
import net.fabricmc.loom.extension.MixinExtension;
import net.fabricmc.loom.task.service.MixinMappingsService;
import net.fabricmc.loom.task.PrepareJarRemapTask;
import net.fabricmc.loom.util.Constants;
/**
@@ -94,7 +94,7 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
String refmapName = Objects.requireNonNull(MixinExtension.getMixinInformationContainer(sourceSet)).refmapNameProvider().get();
Map<String, String> args = new HashMap<>() {{
put(Constants.MixinArguments.IN_MAP_FILE_NAMED_INTERMEDIARY, loom.getMappingsProvider().tinyMappings.toFile().getCanonicalPath());
put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, MixinMappingsService.getMixinMappingFile(project, sourceSet).getCanonicalPath());
put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, getMixinMappingsForSourceSet(project, sourceSet).getCanonicalPath());
put(Constants.MixinArguments.OUT_REFMAP_FILE, getRefmapDestination(task, refmapName));
put(Constants.MixinArguments.DEFAULT_OBFUSCATION_ENV, "named:" + loom.getMixin().getRefmapTargetNamespace().get());
put(Constants.MixinArguments.QUIET, "true");
@@ -111,6 +111,9 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
args.put("AMSG_" + key, value);
});
// Ensure that all of the mixin mappings have been generated before we create the mixin mappings.
runBeforePrepare(project, task);
project.getLogger().debug("Outputting refmap to dir: " + getRefmapDestinationDir(task) + " for compile task: " + task);
args.forEach((k, v) -> passArgument(task, k, v));
} catch (IOException e) {
@@ -143,6 +146,12 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
}
}
private void runBeforePrepare(Project project, Task compileTask) {
project.getGradle().allprojects(otherProject -> {
otherProject.getTasks().withType(PrepareJarRemapTask.class, prepareRemapTask -> prepareRemapTask.mustRunAfter(compileTask));
});
}
private static void checkPattern(String input, Pattern pattern) {
final Matcher matcher = pattern.matcher(input);
@@ -150,4 +159,9 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
throw new IllegalArgumentException("Mixin argument (%s) does not match pattern (%s)".formatted(input, pattern.toString()));
}
}
public static File getMixinMappingsForSourceSet(Project project, SourceSet sourceSet) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
return new File(extension.getFiles().getProjectBuildCache(), "mixin-map-" + extension.getMappingsProvider().mappingsIdentifier() + "." + sourceSet.getName() + ".tiny");
}
}

View File

@@ -30,6 +30,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.function.Consumer;
import org.gradle.api.NamedDomainObjectProvider;
import org.gradle.api.Project;
@@ -63,6 +64,8 @@ import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.ExceptionUtil;
import net.fabricmc.loom.util.gradle.GradleUtils;
import net.fabricmc.loom.util.gradle.SourceSetHelper;
import net.fabricmc.loom.util.service.ScopedSharedServiceManager;
import net.fabricmc.loom.util.service.SharedServiceManager;
public final class CompileConfiguration {
private CompileConfiguration() {
@@ -126,7 +129,7 @@ public final class CompileConfiguration {
javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath()));
});
GradleUtils.afterSuccessfulEvaluation(project, () -> {
afterEvaluationWithService(project, (serviceManager) -> {
MinecraftSourceSets.get(project).afterEvaluate(project);
final boolean previousRefreshDeps = extension.refreshDeps();
@@ -137,14 +140,14 @@ public final class CompileConfiguration {
}
try {
setupMinecraft(project);
setupMinecraft(project, serviceManager);
} catch (Exception e) {
throw ExceptionUtil.createDescriptiveWrapper(RuntimeException::new, "Failed to setup Minecraft", e);
}
LoomDependencyManager dependencyManager = new LoomDependencyManager();
extension.setDependencyManager(dependencyManager);
dependencyManager.handleDependencies(project);
dependencyManager.handleDependencies(project, serviceManager);
releaseLock(project);
extension.setRefreshDeps(previousRefreshDeps);
@@ -178,7 +181,7 @@ public final class CompileConfiguration {
}
// This is not thread safe across projects synchronize it here just to be sure, might be possible to move this further down, but for now this will do.
private static synchronized void setupMinecraft(Project project) throws Exception {
private static synchronized void setupMinecraft(Project project, SharedServiceManager serviceManager) throws Exception {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final MinecraftJarConfiguration jarConfiguration = extension.getMinecraftJarConfiguration().get();
@@ -188,7 +191,7 @@ public final class CompileConfiguration {
minecraftProvider.provide();
final DependencyInfo mappingsDep = DependencyInfo.create(project, Constants.Configurations.MAPPINGS);
final MappingsProviderImpl mappingsProvider = MappingsProviderImpl.getInstance(project, mappingsDep, minecraftProvider);
final MappingsProviderImpl mappingsProvider = MappingsProviderImpl.getInstance(serviceManager, project, mappingsDep, minecraftProvider);
extension.setMappingsProvider(mappingsProvider);
mappingsProvider.applyToProject(project, mappingsDep);
@@ -331,4 +334,12 @@ public final class CompileConfiguration {
private static void finalizedBy(Project project, String a, String b) {
project.getTasks().named(a).configure(task -> task.finalizedBy(project.getTasks().named(b)));
}
private static void afterEvaluationWithService(Project project, Consumer<SharedServiceManager> consumer) {
GradleUtils.afterSuccessfulEvaluation(project, () -> {
try (var serviceManager = new ScopedSharedServiceManager()) {
consumer.accept(serviceManager);
}
});
}
}

View File

@@ -44,9 +44,10 @@ import net.fabricmc.loom.configuration.mods.ModConfigurationRemapper;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.SourceRemapper;
import net.fabricmc.loom.util.ZipUtils;
import net.fabricmc.loom.util.service.SharedServiceManager;
public class LoomDependencyManager {
public void handleDependencies(Project project) {
public void handleDependencies(Project project, SharedServiceManager serviceManager) {
List<Runnable> afterTasks = new ArrayList<>();
project.getLogger().info(":setting up loom dependencies");
@@ -78,7 +79,7 @@ public class LoomDependencyManager {
SourceRemapper sourceRemapper = new SourceRemapper(project, true);
String mappingsIdentifier = extension.getMappingsProvider().mappingsIdentifier();
ModConfigurationRemapper.supplyModConfigurations(project, mappingsIdentifier, extension, sourceRemapper);
ModConfigurationRemapper.supplyModConfigurations(project, serviceManager, mappingsIdentifier, extension, sourceRemapper);
sourceRemapper.remapAll();

View File

@@ -58,6 +58,7 @@ import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.OperatingSystem;
import net.fabricmc.loom.util.SourceRemapper;
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
import net.fabricmc.loom.util.service.SharedServiceManager;
@SuppressWarnings("UnstableApiUsage")
public class ModConfigurationRemapper {
@@ -65,7 +66,7 @@ public class ModConfigurationRemapper {
// This can happen when the dependency is a FileCollectionDependency or from a flatDir repository.
public static final String MISSING_GROUP = "unspecified";
public static void supplyModConfigurations(Project project, String mappingsSuffix, LoomGradleExtension extension, SourceRemapper sourceRemapper) {
public static void supplyModConfigurations(Project project, SharedServiceManager serviceManager, String mappingsSuffix, LoomGradleExtension extension, SourceRemapper sourceRemapper) {
final DependencyHandler dependencies = project.getDependencies();
for (RemapConfigurationSettings entry : extension.getRemapConfigurations()) {
@@ -110,7 +111,7 @@ public class ModConfigurationRemapper {
if (!toRemap.isEmpty()) {
try {
new ModProcessor(project, sourceConfig).processMods(toRemap);
new ModProcessor(project, sourceConfig, serviceManager).processMods(toRemap);
} catch (IOException e) {
throw new UncheckedIOException("Failed to remap mods", e);
}

View File

@@ -53,6 +53,7 @@ import net.fabricmc.loom.util.TinyRemapperHelper;
import net.fabricmc.loom.util.ZipUtils;
import net.fabricmc.loom.util.kotlin.KotlinClasspathService;
import net.fabricmc.loom.util.kotlin.KotlinRemapperClassloader;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.tinyremapper.InputTag;
import net.fabricmc.tinyremapper.NonClassCopyMode;
import net.fabricmc.tinyremapper.OutputConsumerPath;
@@ -64,10 +65,12 @@ public class ModProcessor {
private final Project project;
private final Configuration sourceConfiguration;
private final SharedServiceManager serviceManager;
public ModProcessor(Project project, Configuration sourceConfiguration) {
public ModProcessor(Project project, Configuration sourceConfiguration, SharedServiceManager serviceManager) {
this.project = project;
this.sourceConfiguration = sourceConfiguration;
this.serviceManager = serviceManager;
}
public void processMods(List<ModDependency> remapList) throws IOException {
@@ -101,7 +104,7 @@ public class ModProcessor {
.withMappings(TinyRemapperHelper.create(mappingsProvider.getMappings(), fromM, toM, false))
.renameInvalidLocals(false);
final KotlinClasspathService kotlinClasspathService = KotlinClasspathService.getOrCreateIfRequired(project);
final KotlinClasspathService kotlinClasspathService = KotlinClasspathService.getOrCreateIfRequired(serviceManager, project);
KotlinRemapperClassloader kotlinRemapperClassloader = null;
if (kotlinClasspathService != null) {

View File

@@ -38,6 +38,7 @@ import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.layered.MappingContext;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
import net.fabricmc.loom.util.download.DownloadBuilder;
import net.fabricmc.loom.util.service.ScopedSharedServiceManager;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
public class GradleMappingContext implements MappingContext {
@@ -66,7 +67,11 @@ public class GradleMappingContext implements MappingContext {
@Override
public Supplier<MemoryMappingTree> intermediaryTree() {
return () -> IntermediateMappingsService.getInstance(project, minecraftProvider()).getMemoryMappingTree();
return () -> {
try (var serviceManager = new ScopedSharedServiceManager()) {
return IntermediateMappingsService.getInstance(serviceManager, project, minecraftProvider()).getMemoryMappingTree();
}
};
}
@Override

View File

@@ -56,12 +56,12 @@ public final class IntermediateMappingsService implements SharedService {
this.intermediaryTiny = intermediaryTiny;
}
public static synchronized IntermediateMappingsService getInstance(Project project, MinecraftProvider minecraftProvider) {
public static synchronized IntermediateMappingsService getInstance(SharedServiceManager sharedServiceManager, Project project, MinecraftProvider minecraftProvider) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final IntermediateMappingsProvider intermediateProvider = extension.getIntermediateMappingsProvider();
final String id = "IntermediateMappingsService:%s:%s".formatted(intermediateProvider.getName(), intermediateProvider.getMinecraftVersion().get());
return SharedServiceManager.get(project).getOrCreateService(id, () -> create(intermediateProvider, minecraftProvider));
return sharedServiceManager.getOrCreateService(id, () -> create(intermediateProvider, minecraftProvider));
}
@VisibleForTesting

View File

@@ -98,9 +98,9 @@ public class MappingsProviderImpl implements MappingsProvider, SharedService {
this.intermediaryService = intermediaryService;
}
public static synchronized MappingsProviderImpl getInstance(Project project, DependencyInfo dependency, MinecraftProvider minecraftProvider) {
return SharedServiceManager.get(project).getOrCreateService("MappingsProvider:%s:%s".formatted(dependency.getDepString(), minecraftProvider.minecraftVersion()), () -> {
Supplier<IntermediateMappingsService> intermediaryService = Suppliers.memoize(() -> IntermediateMappingsService.getInstance(project, minecraftProvider));
public static synchronized MappingsProviderImpl getInstance(SharedServiceManager sharedServiceManager, Project project, DependencyInfo dependency, MinecraftProvider minecraftProvider) {
return sharedServiceManager.getOrCreateService("MappingsProvider:%s:%s".formatted(dependency.getDepString(), minecraftProvider.minecraftVersion()), () -> {
Supplier<IntermediateMappingsService> intermediaryService = Suppliers.memoize(() -> IntermediateMappingsService.getInstance(sharedServiceManager, project, minecraftProvider));
return create(dependency, minecraftProvider, intermediaryService);
});
}

View File

@@ -45,10 +45,12 @@ import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Internal;
import org.gradle.build.event.BuildEventsListenerRegistry;
import org.gradle.jvm.tasks.Jar;
import org.gradle.workers.WorkAction;
import org.gradle.workers.WorkParameters;
@@ -89,15 +91,23 @@ public abstract class AbstractRemapJarTask extends Jar {
@Inject
protected abstract WorkerExecutor getWorkerExecutor();
@Inject
protected abstract BuildEventsListenerRegistry getBuildEventsListenerRegistry();
@Input
public abstract Property<Boolean> getIncludesClientOnlyClasses();
private final Provider<JarManifestService> jarManifestServiceProvider;
@Inject
public AbstractRemapJarTask() {
getSourceNamespace().convention(MappingsNamespace.NAMED.toString()).finalizeValueOnRead();
getTargetNamespace().convention(MappingsNamespace.INTERMEDIARY.toString()).finalizeValueOnRead();
getRemapperIsolation().convention(false).finalizeValueOnRead();
getIncludesClientOnlyClasses().convention(false).finalizeValueOnRead();
jarManifestServiceProvider = JarManifestService.get(getProject());
usesService(jarManifestServiceProvider);
}
public final <P extends AbstractRemapParams> void submitWork(Class<? extends AbstractRemapAction<P>> workAction, Action<P> action) {
@@ -113,7 +123,7 @@ public abstract class AbstractRemapJarTask extends Jar {
params.getArchivePreserveFileTimestamps().set(isPreserveFileTimestamps());
params.getArchiveReproducibleFileOrder().set(isReproducibleFileOrder());
params.getJarManifestService().set(JarManifestService.get(getProject()));
params.getJarManifestService().set(jarManifestServiceProvider);
if (getIncludesClientOnlyClasses().get()) {
final List<String> clientOnlyEntries = getClientOnlyEntries();

View File

@@ -78,7 +78,7 @@ public abstract class PrepareJarRemapTask extends AbstractLoomTask {
final WorkQueue workQueue = getWorkerExecutor().noIsolation();
workQueue.submit(ReadInputsAction.class, params -> {
params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(getProject(), remapJarTask.getTinyRemapperService()));
params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(remapJarTask.getTinyRemapperService()));
params.getInputFile().set(getInputFile());
});
}

View File

@@ -46,11 +46,13 @@ import org.gradle.api.file.FileCollection;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskAction;
import org.jetbrains.annotations.ApiStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -71,6 +73,7 @@ import net.fabricmc.loom.util.SidedClassVisitor;
import net.fabricmc.loom.util.ZipUtils;
import net.fabricmc.loom.util.fmj.FabricModJson;
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
import net.fabricmc.loom.util.service.BuildSharedServiceManager;
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
import net.fabricmc.tinyremapper.OutputConsumerPath;
import net.fabricmc.tinyremapper.TinyRemapper;
@@ -82,11 +85,18 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
@Input
public abstract Property<Boolean> getAddNestedDependencies();
private Supplier<TinyRemapperService> tinyRemapperService = Suppliers.memoize(() -> TinyRemapperService.getOrCreate(this));
@Input
@ApiStatus.Internal
public abstract Property<Boolean> getUseMixinAP();
private final Provider<BuildSharedServiceManager> serviceManagerProvider;
private final Supplier<TinyRemapperService> tinyRemapperService;
@Inject
public RemapJarTask() {
super();
serviceManagerProvider = BuildSharedServiceManager.createForTask(this, getBuildEventsListenerRegistry());
tinyRemapperService = Suppliers.memoize(() -> TinyRemapperService.getOrCreate(serviceManagerProvider.get().get(), this));
getClasspath().from(getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME));
getAddNestedDependencies().convention(true).finalizeValueOnRead();
@@ -94,6 +104,8 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
Configuration includeConfiguration = getProject().getConfigurations().getByName(Constants.Configurations.INCLUDE);
getNestedJars().from(new IncludedJarFactory(getProject()).getNestedJars(includeConfiguration));
getUseMixinAP().set(LoomGradleExtension.get(getProject()).getMixin().getUseLegacyMixinAp());
setupPreparationTask();
}
@@ -115,20 +127,18 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
@TaskAction
public void run() {
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
submitWork(RemapAction.class, params -> {
if (getAddNestedDependencies().get()) {
params.getNestedJars().from(getNestedJars());
}
params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(getProject(), tinyRemapperService.get()));
params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(tinyRemapperService.get()));
params.getRemapClasspath().from(getClasspath());
final boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get();
params.getUseMixinExtension().set(!legacyMixin);
final boolean mixinAp = getUseMixinAP().get();
params.getUseMixinExtension().set(!mixinAp);
if (legacyMixin) {
if (mixinAp) {
setupLegacyMixinRefmapRemapping(params);
}
});

View File

@@ -32,6 +32,7 @@ import javax.inject.Inject;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskAction;
import org.slf4j.Logger;
@@ -39,12 +40,16 @@ import org.slf4j.LoggerFactory;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
import net.fabricmc.loom.task.service.SourceRemapperService;
import net.fabricmc.loom.util.service.BuildSharedServiceManager;
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
public abstract class RemapSourcesJarTask extends AbstractRemapJarTask {
private final Provider<BuildSharedServiceManager> serviceManagerProvider;
@Inject
public RemapSourcesJarTask() {
super();
serviceManagerProvider = BuildSharedServiceManager.createForTask(this, getBuildEventsListenerRegistry());
getClasspath().from(getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME));
}
@@ -52,7 +57,7 @@ public abstract class RemapSourcesJarTask extends AbstractRemapJarTask {
@TaskAction
public void run() {
submitWork(RemapSourcesAction.class, params -> {
params.getSourcesRemapperServiceUuid().set(UnsafeWorkQueueHelper.create(getProject(), SourceRemapperService.create(this)));
params.getSourcesRemapperServiceUuid().set(UnsafeWorkQueueHelper.create(SourceRemapperService.create(serviceManagerProvider.get().get(), this)));
});
}

View File

@@ -40,6 +40,7 @@ import org.gradle.util.GradleVersion;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.LoomGradlePlugin;
import net.fabricmc.loom.configuration.InstallerData;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.tinyremapper.TinyRemapper;
@@ -63,10 +64,10 @@ public abstract class JarManifestService implements BuildService<JarManifestServ
params.getGradleVersion().set(GradleVersion.current().getVersion());
params.getLoomVersion().set(LoomGradlePlugin.LOOM_VERSION);
params.getMCEVersion().set(Constants.Dependencies.Versions.MIXIN_COMPILE_EXTENSIONS);
params.getMinecraftVersion().set(extension.getMinecraftProvider().minecraftVersion());
params.getMinecraftVersion().set(project.provider(() -> extension.getMinecraftProvider().minecraftVersion()));
params.getTinyRemapperVersion().set(tinyRemapperVersion.orElse("unknown"));
params.getFabricLoaderVersion().set(getLoaderVersion(project).orElse("unknown"));
params.getMixinVersion().set(getMixinVersion(project).orElse(new MixinVersion("unknown", "unknown")));
params.getFabricLoaderVersion().set(project.provider(() -> Optional.ofNullable(extension.getInstallerData()).map(InstallerData::version).orElse("unknown")));
params.getMixinVersion().set(getMixinVersion(project));
});
});
}
@@ -98,31 +99,23 @@ public abstract class JarManifestService implements BuildService<JarManifestServ
}
}
private static Optional<String> getLoaderVersion(Project project) {
LoomGradleExtension extension = LoomGradleExtension.get(project);
if (extension.getInstallerData() == null) {
project.getLogger().warn("Could not determine fabric loader version for jar manifest");
return Optional.empty();
}
return Optional.of(extension.getInstallerData().version());
}
private record MixinVersion(String group, String version) implements Serializable { }
private static Optional<MixinVersion> getMixinVersion(Project project) {
// Not super ideal that this uses the mod compile classpath, should prob look into making this not a thing at somepoint
Optional<Dependency> dependency = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES)
.getDependencies()
.stream()
.filter(dep -> "sponge-mixin".equals(dep.getName()))
.findFirst();
private static Provider<MixinVersion> getMixinVersion(Project project) {
return project.getConfigurations().named(Constants.Configurations.LOADER_DEPENDENCIES).map(configuration -> {
// Not super ideal that this uses the mod compile classpath, should prob look into making this not a thing at somepoint
Optional<Dependency> dependency = configuration
.getDependencies()
.stream()
.filter(dep -> "sponge-mixin".equals(dep.getName()))
.findFirst();
if (dependency.isEmpty()) {
project.getLogger().warn("Could not determine Mixin version for jar manifest");
}
if (dependency.isEmpty()) {
project.getLogger().warn("Could not determine Mixin version for jar manifest");
}
return dependency.map(d -> new MixinVersion(d.getGroup(), d.getVersion()));
return dependency.map(d -> new MixinVersion(d.getGroup(), d.getVersion()))
.orElse(new MixinVersion("unknown", "unknown"));
});
}
}

View File

@@ -42,21 +42,17 @@ import net.fabricmc.tinyremapper.IMappingProvider;
public final class MappingsService implements SharedService {
private record Options(Path mappingsFile, String from, String to, boolean remapLocals) { }
public static MappingsService create(Project project, String name, Path mappingsFile, String from, String to, boolean remapLocals) {
return create(SharedServiceManager.get(project), name, mappingsFile, from, to, remapLocals);
}
public static synchronized MappingsService create(SharedServiceManager sharedServiceManager, String name, Path mappingsFile, String from, String to, boolean remapLocals) {
final Options options = new Options(mappingsFile, from, to, remapLocals);
final String id = name + options.hashCode();
return sharedServiceManager.getOrCreateService(id, () -> new MappingsService(options));
}
public static MappingsService createDefault(Project project, String from, String to) {
public static MappingsService createDefault(Project project, SharedServiceManager serviceManager, String from, String to) {
final MappingsProviderImpl mappingsProvider = LoomGradleExtension.get(project).getMappingsProvider();
final String name = mappingsProvider.getBuildServiceName("mappingsProvider", from, to);
return MappingsService.create(project, name, mappingsProvider.tinyMappings, from, to, false);
return MappingsService.create(serviceManager, name, mappingsProvider.tinyMappings, from, to, false);
}
private final Options options;

View File

@@ -1,70 +0,0 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2022 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.task.service;
import java.io.File;
import java.util.HashSet;
import org.gradle.api.Project;
import org.gradle.api.tasks.SourceSet;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
import net.fabricmc.loom.util.service.SharedService;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.tinyremapper.IMappingProvider;
public final class MixinMappingsService implements SharedService {
private final SharedServiceManager sharedServiceManager;
private final HashSet<File> mixinMappings = new HashSet<>();
private MixinMappingsService(SharedServiceManager sharedServiceManager) {
this.sharedServiceManager = sharedServiceManager;
}
public static File getMixinMappingFile(Project project, SourceSet sourceSet) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
File mixinMapping = new File(extension.getFiles().getProjectBuildCache(), "mixin-map-" + extension.getMappingsProvider().mappingsIdentifier() + "." + sourceSet.getName() + ".tiny");
getService(SharedServiceManager.get(project), extension.getMappingsProvider()).mixinMappings.add(mixinMapping);
return mixinMapping;
}
static synchronized MixinMappingsService getService(SharedServiceManager sharedServiceManager, MappingsProviderImpl mappingsProvider) {
return sharedServiceManager.getOrCreateService("MixinMappings-" + mappingsProvider.mappingsIdentifier(), () -> new MixinMappingsService(sharedServiceManager));
}
IMappingProvider getMappingProvider(String from, String to) {
return out -> {
for (File mixinMapping : mixinMappings) {
if (!mixinMapping.exists()) continue;
MappingsService service = MappingsService.create(sharedServiceManager, mixinMapping.getAbsolutePath(), mixinMapping.toPath(), from, to, false);
service.getMappingsProvider().load(out);
}
};
}
}

View File

@@ -52,16 +52,15 @@ import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.lorenztiny.TinyMappingsReader;
public final class SourceRemapperService implements SharedService {
public static synchronized SourceRemapperService create(RemapSourcesJarTask task) {
public static synchronized SourceRemapperService create(SharedServiceManager serviceManager, RemapSourcesJarTask task) {
final Project project = task.getProject();
final String to = task.getTargetNamespace().get();
final String from = task.getSourceNamespace().get();
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final SharedServiceManager sharedServiceManager = SharedServiceManager.get(project);
final String id = extension.getMappingsProvider().getBuildServiceName("sourceremapper", from, to);
return sharedServiceManager.getOrCreateService(id, () ->
new SourceRemapperService(MappingsService.createDefault(project, from, to), task.getClasspath()
return serviceManager.getOrCreateService(id, () ->
new SourceRemapperService(MappingsService.createDefault(project, serviceManager, from, to), task.getClasspath()
));
}

View File

@@ -37,10 +37,15 @@ import java.util.Objects;
import java.util.StringJoiner;
import org.gradle.api.Project;
import org.gradle.api.invocation.Gradle;
import org.gradle.api.tasks.SourceSet;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.build.mixin.AnnotationProcessorInvoker;
import net.fabricmc.loom.task.AbstractRemapJarTask;
import net.fabricmc.loom.util.gradle.GradleUtils;
import net.fabricmc.loom.util.gradle.SourceSetHelper;
import net.fabricmc.loom.util.kotlin.KotlinClasspath;
import net.fabricmc.loom.util.kotlin.KotlinClasspathService;
import net.fabricmc.loom.util.kotlin.KotlinRemapperClassloader;
@@ -51,14 +56,13 @@ import net.fabricmc.tinyremapper.InputTag;
import net.fabricmc.tinyremapper.TinyRemapper;
public class TinyRemapperService implements SharedService {
public static synchronized TinyRemapperService getOrCreate(AbstractRemapJarTask remapJarTask) {
public static synchronized TinyRemapperService getOrCreate(SharedServiceManager serviceManager, AbstractRemapJarTask remapJarTask) {
final Project project = remapJarTask.getProject();
final String to = remapJarTask.getTargetNamespace().get();
final String from = remapJarTask.getSourceNamespace().get();
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final SharedServiceManager sharedServiceManager = SharedServiceManager.get(project);
final boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get();
final @Nullable KotlinClasspathService kotlinClasspathService = KotlinClasspathService.getOrCreateIfRequired(project);
final @Nullable KotlinClasspathService kotlinClasspathService = KotlinClasspathService.getOrCreateIfRequired(serviceManager, project);
// Generates an id that is used to share the remapper across projects. This tasks in the remap jar task name to handle custom remap jar tasks separately.
final var joiner = new StringJoiner(":");
@@ -75,12 +79,12 @@ public class TinyRemapperService implements SharedService {
final String id = joiner.toString();
TinyRemapperService service = sharedServiceManager.getOrCreateService(id, () -> {
TinyRemapperService service = serviceManager.getOrCreateService(id, () -> {
List<IMappingProvider> mappings = new ArrayList<>();
mappings.add(MappingsService.createDefault(project, from, to).getMappingsProvider());
mappings.add(MappingsService.createDefault(project, serviceManager, from, to).getMappingsProvider());
if (legacyMixin) {
mappings.add(MixinMappingsService.getService(SharedServiceManager.get(project), extension.getMappingsProvider()).getMappingProvider(from, to));
mappings.add(gradleMixinMappingProvider(serviceManager, project.getGradle(), from, to));
}
return new TinyRemapperService(mappings, !legacyMixin, kotlinClasspathService);
@@ -91,6 +95,22 @@ public class TinyRemapperService implements SharedService {
return service;
}
// Add all of the mixin mappings from all loom projects.
private static IMappingProvider gradleMixinMappingProvider(SharedServiceManager serviceManager, Gradle gradle, String from, String to) {
return out -> GradleUtils.allLoomProjects(gradle, project -> {
for (SourceSet sourceSet : SourceSetHelper.getSourceSets(project)) {
final File mixinMappings = AnnotationProcessorInvoker.getMixinMappingsForSourceSet(project, sourceSet);
if (!mixinMappings.exists()) {
continue;
}
MappingsService service = MappingsService.create(serviceManager, mixinMappings.getAbsolutePath(), mixinMappings.toPath(), from, to, false);
service.getMappingsProvider().load(out);
}
});
}
private TinyRemapper tinyRemapper;
@Nullable
private KotlinRemapperClassloader kotlinRemapperClassloader;

View File

@@ -49,13 +49,6 @@ public interface DeprecationHelper {
public ProjectBased(Project project) {
this.project = project;
project.getGradle().buildFinished(buildResult -> {
if (usingDeprecatedApi.get()) {
project.getLogger().lifecycle("Deprecated Loom APIs were used in this build, making it incompatible with future versions of Loom. "
+ "Use Gradle warning modes to control the verbosity of the warnings.");
}
});
}
@Override

View File

@@ -24,7 +24,10 @@
package net.fabricmc.loom.util.gradle;
import java.util.function.Consumer;
import org.gradle.api.Project;
import org.gradle.api.invocation.Gradle;
public final class GradleUtils {
private GradleUtils() {
@@ -41,4 +44,12 @@ public final class GradleUtils {
afterEvaluate.run();
});
}
public static void allLoomProjects(Gradle gradle, Consumer<Project> consumer) {
gradle.allprojects(project -> {
if (project.getPluginManager().hasPlugin("fabric-loom")) {
consumer.accept(project);
}
});
}
}

View File

@@ -45,6 +45,7 @@ import org.gradle.api.internal.tasks.DefaultSourceSetOutput;
import org.gradle.api.internal.tasks.DefaultTaskDependency;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.SourceSetOutput;
import org.gradle.api.tasks.TaskProvider;
import org.intellij.lang.annotations.Language;
@@ -63,20 +64,23 @@ public final class SourceSetHelper {
private SourceSetHelper() {
}
public static SourceSetContainer getSourceSets(Project project) {
final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
return javaExtension.getSourceSets();
}
/**
* Returns true when the provided project contains the {@link SourceSet}.
*/
public static boolean isSourceSetOfProject(SourceSet sourceSet, Project project) {
if (System.getProperty("fabric-loom.unit.testing") != null) return true;
final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
return javaExtension.getSourceSets().stream()
return getSourceSets(project).stream()
.anyMatch(test -> test == sourceSet); // Ensure we have an identical reference
}
public static SourceSet getSourceSetByName(String name, Project project) {
final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
return javaExtension.getSourceSets().getByName(name);
return getSourceSets(project).getByName(name);
}
public static SourceSet getMainSourceSet(Project project) {
@@ -84,8 +88,7 @@ public final class SourceSetHelper {
}
public static SourceSet createSourceSet(String name, Project project) {
final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
return javaExtension.getSourceSets().create(name);
return getSourceSets(project).create(name);
}
/**

View File

@@ -39,17 +39,16 @@ import net.fabricmc.loom.util.service.SharedServiceManager;
public record KotlinClasspathService(Set<URL> classpath, String version) implements KotlinClasspath, SharedService {
@Nullable
public static KotlinClasspathService getOrCreateIfRequired(Project project) {
public static KotlinClasspathService getOrCreateIfRequired(SharedServiceManager sharedServiceManager, Project project) {
if (!KotlinPluginUtils.hasKotlinPlugin(project)) {
return null;
}
return getOrCreate(project, KotlinPluginUtils.getKotlinPluginVersion(project), KotlinPluginUtils.getKotlinMetadataVersion());
return getOrCreate(sharedServiceManager, project, KotlinPluginUtils.getKotlinPluginVersion(project), KotlinPluginUtils.getKotlinMetadataVersion());
}
public static synchronized KotlinClasspathService getOrCreate(Project project, String kotlinVersion, String kotlinMetadataVersion) {
public static synchronized KotlinClasspathService getOrCreate(SharedServiceManager sharedServiceManager, Project project, String kotlinVersion, String kotlinMetadataVersion) {
final String id = "kotlinclasspath:%s:%s".formatted(kotlinVersion, kotlinMetadataVersion);
final SharedServiceManager sharedServiceManager = SharedServiceManager.get(project);
return sharedServiceManager.getOrCreateService(id, () -> create(project, kotlinVersion, kotlinMetadataVersion));
}

View File

@@ -0,0 +1,90 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2022 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.service;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import org.gradle.api.Task;
import org.gradle.api.provider.Provider;
import org.gradle.api.services.BuildService;
import org.gradle.api.services.BuildServiceParameters;
import org.gradle.build.event.BuildEventsListenerRegistry;
import org.gradle.tooling.events.OperationCompletionListener;
import org.gradle.tooling.events.task.TaskOperationDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class BuildSharedServiceManager implements BuildService<BuildServiceParameters.None> {
private static final Logger LOGGER = LoggerFactory.getLogger(BuildSharedServiceManager.class);
private static final String NAME = "loom:sharedServiceManager";
private SharedServiceManager sharedServiceManager = new BuildSharedServiceManagerImpl();
private final AtomicInteger refCount = new AtomicInteger(0);
public static Provider<BuildSharedServiceManager> createForTask(Task task, BuildEventsListenerRegistry buildEventsListenerRegistry) {
Provider<BuildSharedServiceManager> provider = task.getProject().getGradle().getSharedServices().registerIfAbsent(NAME, BuildSharedServiceManager.class, spec -> {
});
task.usesService(provider);
final BuildSharedServiceManager serviceManager = provider.get();
buildEventsListenerRegistry.onTaskCompletion(registerTaskCompletion(task, serviceManager::onFinish));
int count = serviceManager.refCount.incrementAndGet();
LOGGER.debug("Creating shared service manager provider for task: {} count: {}", task.getName(), count);
return provider;
}
public SharedServiceManager get() {
LOGGER.debug("Shared build service get");
return Objects.requireNonNull(sharedServiceManager);
}
private void onFinish() {
int count = refCount.decrementAndGet();
LOGGER.debug("Build service finish. count: {}", count);
if (count == 0) {
sharedServiceManager.onFinish();
sharedServiceManager = null;
} else if (count < 0) {
throw new IllegalStateException();
}
}
private static Provider<OperationCompletionListener> registerTaskCompletion(Task task, Runnable runnable) {
return task.getProject().provider(() -> event -> {
if (event.getDescriptor() instanceof TaskOperationDescriptor taskDescriptor) {
if (taskDescriptor.getTaskPath().equals(task.getPath())) {
runnable.run();
}
}
});
}
private static final class BuildSharedServiceManagerImpl extends SharedServiceManager {
}
}

View File

@@ -0,0 +1,35 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2022 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.service;
public final class ScopedSharedServiceManager extends SharedServiceManager implements AutoCloseable {
public ScopedSharedServiceManager() {
}
@Override
public void close() {
onFinish();
}
}

View File

@@ -31,33 +31,21 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import org.gradle.BuildResult;
import org.gradle.api.Project;
import org.gradle.api.invocation.Gradle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A simple manager for {@link SharedService} to be used across gradle (sub) projects.
* This is a basic replacement for gradle's build service api.
*/
public final class SharedServiceManager {
private static final Map<Gradle, SharedServiceManager> SERVICE_FACTORY_MAP = new ConcurrentHashMap<>();
private final Gradle gradle;
public abstract class SharedServiceManager {
private static final Logger LOGGER = LoggerFactory.getLogger(BuildSharedServiceManager.class);
private final Map<String, SharedService> sharedServiceMap = new ConcurrentHashMap<>();
private boolean shutdown = false;
private SharedServiceManager(Gradle gradle) {
this.gradle = gradle;
this.gradle.buildFinished(this::onFinish);
}
public static SharedServiceManager get(Project project) {
return get(project.getGradle());
}
public static SharedServiceManager get(Gradle gradle) {
return SERVICE_FACTORY_MAP.computeIfAbsent(gradle, SharedServiceManager::new);
SharedServiceManager() {
LOGGER.info("Creating new SharedServiceManager({})", hashCode());
}
public <S extends SharedService> S getOrCreateService(String id, Supplier<S> function) {
@@ -78,12 +66,12 @@ public final class SharedServiceManager {
}
}
private void onFinish(BuildResult buildResult) {
protected void onFinish() {
synchronized (sharedServiceMap) {
shutdown = true;
}
SERVICE_FACTORY_MAP.remove(gradle);
LOGGER.info("Closing SharedServiceManager({})", hashCode());
final List<IOException> exceptionList = new ArrayList<>();

View File

@@ -28,7 +28,6 @@ import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.gradle.api.Project;
import org.gradle.api.provider.Property;
// Massive hack to work around WorkerExecutor.noIsolation() doing isolation checks.
@@ -38,12 +37,10 @@ public final class UnsafeWorkQueueHelper {
private UnsafeWorkQueueHelper() {
}
public static String create(Project project, SharedService service) {
public static String create(SharedService service) {
final String uuid = UUID.randomUUID().toString();
SERVICE_MAP.put(uuid, service);
// Ensure we don't make a mess if things go wrong.
project.getGradle().buildFinished(buildResult -> SERVICE_MAP.remove(uuid));
return uuid;
}