Merge commit '9157c22448cb4847586772f8028010f717accc14' into dev/1.8

This commit is contained in:
shedaniel
2024-11-16 20:17:29 +08:00
63 changed files with 1034 additions and 972 deletions

View File

@@ -27,7 +27,7 @@ import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.FileSystemUtil;
import net.fabricmc.loom.util.LfWriter;
import net.fabricmc.loom.util.aw2at.Aw2At;
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
import net.fabricmc.loom.util.service.ServiceFactory;
public final class ModBuildExtensions {
public static Set<String> readMixinConfigsFromManifest(File jarFile) {
@@ -49,7 +49,7 @@ public final class ModBuildExtensions {
}
}
public static void convertAwToAt(SetProperty<String> atAccessWidenersProperty, Path outputFile, Property<String> mappingBuildServiceUuid) throws IOException {
public static void convertAwToAt(ServiceFactory serviceFactory, SetProperty<String> atAccessWidenersProperty, Path outputFile, Property<MappingsService.Options> options) throws IOException {
if (!atAccessWidenersProperty.isPresent()) {
return;
}
@@ -84,8 +84,8 @@ public final class ModBuildExtensions {
Files.delete(awPath);
}
MappingsService service = UnsafeWorkQueueHelper.get(mappingBuildServiceUuid, MappingsService.class);
at = at.remap(service.getMemoryMappingTree(), service.getFromNamespace(), service.getToNamespace());
MappingsService service = serviceFactory.get(options);
at = at.remap(service.getMemoryMappingTree(), service.getFrom(), service.getTo());
try (Writer writer = new LfWriter(Files.newBufferedWriter(atPath))) {
AccessTransformFormats.FML.write(writer, at);

View File

@@ -24,6 +24,8 @@
package net.fabricmc.loom.api.remapping;
import java.io.Serializable;
import org.jetbrains.annotations.ApiStatus;
/**
@@ -31,7 +33,7 @@ import org.jetbrains.annotations.ApiStatus;
*
* <p>Design based off of Gradle's {@link org.gradle.workers.WorkParameters}.
*/
public interface RemapperParameters {
public interface RemapperParameters extends Serializable {
final class None implements RemapperParameters {
@ApiStatus.Internal
public static None INSTANCE = new None();

View File

@@ -91,8 +91,8 @@ import net.fabricmc.loom.util.ExceptionUtil;
import net.fabricmc.loom.util.ProcessUtil;
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;
import net.fabricmc.loom.util.service.ScopedServiceFactory;
import net.fabricmc.loom.util.service.ServiceFactory;
public abstract class CompileConfiguration implements Runnable {
@Inject
@@ -110,8 +110,8 @@ public abstract class CompileConfiguration implements Runnable {
javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath()));
});
afterEvaluationWithService((serviceManager) -> {
final ConfigContext configContext = new ConfigContextImpl(getProject(), serviceManager, extension);
afterEvaluationWithService((serviceFactory) -> {
final ConfigContext configContext = new ConfigContextImpl(getProject(), serviceFactory, extension);
MinecraftSourceSets.get(getProject()).afterEvaluate(getProject());
@@ -129,7 +129,7 @@ public abstract class CompileConfiguration implements Runnable {
LoomDependencyManager dependencyManager = new LoomDependencyManager();
extension.setDependencyManager(dependencyManager);
dependencyManager.handleDependencies(getProject(), serviceManager);
dependencyManager.handleDependencies(getProject(), serviceFactory);
} catch (Exception e) {
ExceptionUtil.processException(e, getProject());
disownLock();
@@ -159,7 +159,7 @@ public abstract class CompileConfiguration implements Runnable {
// because of https://github.com/architectury/architectury-loom/issues/72.
if (!ModConfigurationRemapper.isCIBuild()) {
try {
ForgeSourcesRemapper.addBaseForgeSources(getProject());
ForgeSourcesRemapper.addBaseForgeSources(getProject(), configContext.serviceFactory());
} catch (IOException e) {
e.printStackTrace();
}
@@ -225,7 +225,7 @@ public abstract class CompileConfiguration implements Runnable {
setupDependencyProviders(project, extension);
final DependencyInfo mappingsDep = DependencyInfo.create(getProject(), Configurations.MAPPINGS);
final MappingConfiguration mappingConfiguration = MappingConfiguration.create(getProject(), configContext.serviceManager(), mappingsDep, minecraftProvider);
final MappingConfiguration mappingConfiguration = MappingConfiguration.create(getProject(), configContext.serviceFactory(), mappingsDep, minecraftProvider);
extension.setMappingConfiguration(mappingConfiguration);
if (extension.isForgeLike()) {
@@ -241,7 +241,7 @@ public abstract class CompileConfiguration implements Runnable {
}
if (minecraftProvider instanceof ForgeMinecraftProvider patched) {
patched.getPatchedProvider().remapJar();
patched.getPatchedProvider().remapJar(configContext.serviceFactory());
}
// Provide the remapped mc jars
@@ -540,10 +540,12 @@ public abstract class CompileConfiguration implements Runnable {
dependencyProviders.handleDependencies(project);
}
private void afterEvaluationWithService(Consumer<SharedServiceManager> consumer) {
private void afterEvaluationWithService(Consumer<ServiceFactory> consumer) {
GradleUtils.afterSuccessfulEvaluation(getProject(), () -> {
try (var serviceManager = new ScopedSharedServiceManager()) {
consumer.accept(serviceManager);
try (var serviceFactory = new ScopedServiceFactory()) {
consumer.accept(serviceFactory);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
}

View File

@@ -27,10 +27,10 @@ package net.fabricmc.loom.configuration;
import org.gradle.api.Project;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.service.ServiceFactory;
public interface ConfigContext {
Project project();
SharedServiceManager serviceManager();
ServiceFactory serviceFactory();
LoomGradleExtension extension();
}

View File

@@ -27,7 +27,7 @@ package net.fabricmc.loom.configuration;
import org.gradle.api.Project;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.service.ServiceFactory;
public record ConfigContextImpl(Project project, SharedServiceManager serviceManager, LoomGradleExtension extension) implements ConfigContext {
public record ConfigContextImpl(Project project, ServiceFactory serviceFactory, LoomGradleExtension extension) implements ConfigContext {
}

View File

@@ -29,18 +29,18 @@ import org.gradle.api.Project;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.configuration.mods.ModConfigurationRemapper;
import net.fabricmc.loom.util.SourceRemapper;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.service.ServiceFactory;
public class LoomDependencyManager {
public void handleDependencies(Project project, SharedServiceManager serviceManager) {
public void handleDependencies(Project project, ServiceFactory serviceFactory) {
project.getLogger().info(":setting up loom dependencies");
LoomGradleExtension extension = LoomGradleExtension.get(project);
SourceRemapper sourceRemapper = new SourceRemapper(project, serviceManager, true);
SourceRemapper sourceRemapper = new SourceRemapper(project, serviceFactory, true);
String platformSuffix = extension.isForgeLike() ? "_forge" : extension.isQuilt() ? "_arch_quilt" : "";
String mappingsIdentifier = extension.getMappingConfiguration().mappingsIdentifier() + platformSuffix;
ModConfigurationRemapper.supplyModConfigurations(project, serviceManager, mappingsIdentifier, extension, sourceRemapper);
ModConfigurationRemapper.supplyModConfigurations(project, serviceFactory, mappingsIdentifier, extension, sourceRemapper);
sourceRemapper.remapAll();

View File

@@ -68,7 +68,7 @@ import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.ExceptionUtil;
import net.fabricmc.loom.util.SourceRemapper;
import net.fabricmc.loom.util.gradle.SourceSetHelper;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.service.ServiceFactory;
@SuppressWarnings("UnstableApiUsage")
public class ModConfigurationRemapper {
@@ -76,7 +76,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, SharedServiceManager serviceManager, String mappingsSuffix, LoomGradleExtension extension, SourceRemapper sourceRemapper) {
public static void supplyModConfigurations(Project project, ServiceFactory serviceFactory, String mappingsSuffix, LoomGradleExtension extension, SourceRemapper sourceRemapper) {
final DependencyHandler dependencies = project.getDependencies();
// The configurations where the source and remapped artifacts go.
// key: source, value: target
@@ -202,7 +202,7 @@ public class ModConfigurationRemapper {
if (!toRemap.isEmpty()) {
try {
new ModProcessor(project, sourceConfig, serviceManager).processMods(toRemap);
new ModProcessor(project, sourceConfig, serviceFactory).processMods(toRemap);
} catch (IOException e) {
throw new UncheckedIOException("Failed to remap mods", e);
}

View File

@@ -64,7 +64,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.loom.util.service.ServiceFactory;
import net.fabricmc.loom.util.srg.AtClassRemapper;
import net.fabricmc.loom.util.srg.CoreModClassRemapper;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
@@ -81,12 +81,12 @@ public class ModProcessor {
private final Project project;
private final Configuration sourceConfiguration;
private final SharedServiceManager serviceManager;
private final ServiceFactory serviceFactory;
public ModProcessor(Project project, Configuration sourceConfiguration, SharedServiceManager serviceManager) {
public ModProcessor(Project project, Configuration sourceConfiguration, ServiceFactory serviceFactory) {
this.project = project;
this.sourceConfiguration = sourceConfiguration;
this.serviceManager = serviceManager;
this.serviceFactory = serviceFactory;
}
public void processMods(List<ModDependency> remapList) throws IOException {
@@ -174,7 +174,7 @@ public class ModProcessor {
}
MappingOption mappingOption = MappingOption.forPlatform(extension);
MemoryMappingTree mappings = mappingConfiguration.getMappingsService(serviceManager, mappingOption).getMappingTree();
MemoryMappingTree mappings = mappingConfiguration.getMappingsService(project, serviceManager, mappingOption).getMappingTree();
LoggerFilter.replaceSystemOut();
TinyRemapper.Builder builder = TinyRemapper.newRemapper()
@@ -183,7 +183,7 @@ public class ModProcessor {
.renameInvalidLocals(false)
.extraAnalyzeVisitor(AccessWidenerAnalyzeVisitorProvider.createFromMods(fromM, remapList, extension.getPlatform().get()));
final KotlinClasspathService kotlinClasspathService = KotlinClasspathService.getOrCreateIfRequired(serviceManager, project);
final KotlinClasspathService kotlinClasspathService = serviceFactory.getOrNull(KotlinClasspathService.createOptions(project));
KotlinRemapperClassloader kotlinRemapperClassloader = null;
if (kotlinClasspathService != null) {
@@ -201,7 +201,7 @@ public class ModProcessor {
}
for (RemapperExtensionHolder holder : extension.getRemapperExtensions().get()) {
holder.apply(builder, fromM, toM, project.getObjects());
holder.apply(builder, fromM, toM);
}
final TinyRemapper remapper = builder.build();

View File

@@ -41,7 +41,7 @@ public final class ContextImplHelper {
public static LazyCloseable<TinyRemapper> createRemapper(ConfigContext configContext, MappingsNamespace from, MappingsNamespace to) {
return new LazyCloseable<>(() -> {
try {
TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(configContext.project(), configContext.serviceManager(), from.toString(), to.toString());
TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(configContext.project(), configContext.serviceFactory(), from.toString(), to.toString());
for (Path minecraftJar : configContext.extension().getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
tinyRemapper.readClassPath(minecraftJar);

View File

@@ -66,6 +66,6 @@ public record ProcessorContextImpl(ConfigContext configContext, MinecraftJar min
public MemoryMappingTree getMappings() {
LoomGradleExtension extension = LoomGradleExtension.get(configContext().project());
final MappingOption mappingOption = MappingOption.forPlatform(extension);
return extension.getMappingConfiguration().getMappingsService(configContext().serviceManager(), mappingOption).getMappingTree();
return extension.getMappingConfiguration().getMappingsService(configContext().project(), configContext().serviceFactory(), mappingOption).getMappingTree();
}
}

View File

@@ -55,6 +55,9 @@ import de.oceanlabs.mcp.mcinjector.adaptors.ParameterAnnotationFixer;
import dev.architectury.loom.forge.UserdevConfig;
import dev.architectury.loom.util.MappingOption;
import dev.architectury.loom.util.TempFiles;
import net.fabricmc.loom.util.service.ServiceFactory;
import org.gradle.api.Project;
import org.gradle.api.logging.LogLevel;
import org.gradle.api.logging.Logger;
@@ -83,8 +86,6 @@ import net.fabricmc.loom.util.ThreadingUtils;
import net.fabricmc.loom.util.TinyRemapperHelper;
import net.fabricmc.loom.util.ZipUtils;
import net.fabricmc.loom.util.function.FsPathConsumer;
import net.fabricmc.loom.util.service.ScopedSharedServiceManager;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.srg.CoreModClassRemapper;
import net.fabricmc.loom.util.srg.InnerClassRemapper;
import net.fabricmc.mappingio.tree.MappingTree;
@@ -207,12 +208,9 @@ public class MinecraftPatchedProvider {
}
}
public void remapJar() throws Exception {
public void remapJar(ServiceFactory serviceFactory) throws Exception {
if (dirty) {
try (var serviceManager = new ScopedSharedServiceManager()) {
remapPatchedJar(serviceManager);
}
remapPatchedJar(serviceFactory);
fillClientExtraJar();
}
@@ -226,9 +224,9 @@ public class MinecraftPatchedProvider {
copyNonClassFiles(minecraftProvider.getMinecraftClientJar().toPath(), minecraftClientExtra);
}
private TinyRemapper buildRemapper(SharedServiceManager serviceManager, Path input) throws IOException {
private TinyRemapper buildRemapper(ServiceFactory serviceFactory, Path input) throws IOException {
final MappingOption mappingOption = MappingOption.forPlatform(getExtension());
TinyMappingsService mappingsService = getExtension().getMappingConfiguration().getMappingsService(serviceManager, mappingOption);
TinyMappingsService mappingsService = getExtension().getMappingConfiguration().getMappingsService(project, serviceFactory, mappingOption);
final String sourceNamespace = IntermediaryNamespaces.intermediary(project);
MemoryMappingTree mappings = mappingsService.getMappingTree();
@@ -408,7 +406,7 @@ public class MinecraftPatchedProvider {
project.getLogger().lifecycle(":access transformed minecraft in " + stopwatch.stop());
}
private void remapPatchedJar(SharedServiceManager serviceManager) throws Exception {
private void remapPatchedJar(ServiceFactory serviceFactory) throws Exception {
logger.lifecycle(":remapping minecraft (TinyRemapper, srg -> official)");
Path mcInput = minecraftPatchedIntermediateAtJar;
Path mcOutput = minecraftPatchedJar;
@@ -416,7 +414,7 @@ public class MinecraftPatchedProvider {
Path forgeUserdevJar = getForgeUserdevJar().toPath();
Files.deleteIfExists(mcOutput);
TinyRemapper remapper = buildRemapper(serviceManager, mcInput);
TinyRemapper remapper = buildRemapper(serviceFactory, mcInput);
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(mcOutput).build()) {
outputConsumer.addNonClassFiles(mcInput);
@@ -435,13 +433,13 @@ public class MinecraftPatchedProvider {
}
copyUserdevFiles(forgeUserdevJar, mcOutput);
remapCoreMods(mcOutput, serviceManager);
remapCoreMods(mcOutput, serviceFactory);
applyLoomPatchVersion(mcOutput);
}
private void remapCoreMods(Path patchedJar, SharedServiceManager serviceManager) throws Exception {
private void remapCoreMods(Path patchedJar, ServiceFactory serviceFactory) throws Exception {
final MappingOption mappingOption = MappingOption.forPlatform(getExtension());
final TinyMappingsService mappingsService = getExtension().getMappingConfiguration().getMappingsService(serviceManager, mappingOption);
final TinyMappingsService mappingsService = getExtension().getMappingConfiguration().getMappingsService(project, serviceFactory, mappingOption);
final MappingTree mappings = mappingsService.getMappingTree();
CoreModClassRemapper.remapJar(project, getExtension().getPlatform().get(), patchedJar, mappings);
}

View File

@@ -25,6 +25,8 @@
package net.fabricmc.loom.configuration.providers.mappings;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.function.Supplier;
@@ -39,7 +41,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.loom.util.service.ScopedServiceFactory;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
public class GradleMappingContext implements MappingContext {
@@ -74,8 +76,11 @@ public class GradleMappingContext implements MappingContext {
@Override
public Supplier<MemoryMappingTree> intermediaryTree() {
return () -> {
try (var serviceManager = new ScopedSharedServiceManager()) {
return IntermediateMappingsService.getInstance(serviceManager, project, minecraftProvider()).getMemoryMappingTree();
try (var serviceFactory = new ScopedServiceFactory()) {
IntermediateMappingsService intermediateMappingsService = serviceFactory.get(IntermediateMappingsService.createOptions(project, minecraftProvider()));
return intermediateMappingsService.getMemoryMappingTree();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
};
}

View File

@@ -31,77 +31,101 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.Objects;
import java.util.function.Supplier;
import com.google.common.base.Suppliers;
import org.gradle.api.Project;
import org.gradle.api.file.RegularFileProperty;
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.jetbrains.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
import net.fabricmc.loom.util.service.SharedService;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.service.Service;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.loom.util.service.ServiceType;
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
import net.fabricmc.mappingio.format.tiny.Tiny2FileReader;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
public final class IntermediateMappingsService implements SharedService {
private final Path intermediaryTiny;
private final String expectedSrcNs;
public final class IntermediateMappingsService extends Service<IntermediateMappingsService.Options> {
public static final ServiceType<Options, IntermediateMappingsService> TYPE = new ServiceType<>(Options.class, IntermediateMappingsService.class);
private static final Logger LOGGER = LoggerFactory.getLogger(IntermediateMappingsService.class);
public interface Options extends Service.Options {
@InputFile
RegularFileProperty getIntermediaryTiny();
@Input
Property<String> getExpectedSrcNs();
@Input
Property<String> getMinecraftVersion();
}
private final Supplier<MemoryMappingTree> memoryMappingTree = Suppliers.memoize(this::createMemoryMappingTree);
private IntermediateMappingsService(Path intermediaryTiny, String expectedSrcNs) {
this.intermediaryTiny = intermediaryTiny;
this.expectedSrcNs = expectedSrcNs;
public IntermediateMappingsService(Options options, ServiceFactory serviceFactory) {
super(options, serviceFactory);
}
public static synchronized IntermediateMappingsService getInstance(SharedServiceManager sharedServiceManager, Project project, MinecraftProvider minecraftProvider) {
public static Provider<Options> createOptions(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.getOrCreateService(id, () -> create(intermediateProvider, minecraftProvider, project));
}
@VisibleForTesting
public static IntermediateMappingsService create(IntermediateMappingsProvider intermediateMappingsProvider, MinecraftProvider minecraftProvider, Project project) {
final Path intermediaryTiny = minecraftProvider.file(intermediateMappingsProvider.getName() + ".tiny").toPath();
final Path intermediaryTiny = minecraftProvider.file(intermediateProvider.getName() + ".tiny").toPath();
try {
if (intermediateMappingsProvider instanceof IntermediateMappingsProviderInternal internal) {
if (intermediateProvider instanceof IntermediateMappingsProviderInternal internal) {
internal.provide(intermediaryTiny, project);
} else {
intermediateMappingsProvider.provide(intermediaryTiny);
intermediateProvider.provide(intermediaryTiny);
}
} catch (IOException e) {
try {
Files.deleteIfExists(intermediaryTiny);
} catch (IOException ex) {
ex.printStackTrace();
LOGGER.warn("Failed to delete intermediary mappings file", ex);
}
throw new UncheckedIOException("Failed to provide intermediate mappings", e);
}
return createOptions(project, minecraftProvider, intermediaryTiny);
}
private static Provider<Options> createOptions(Project project, MinecraftProvider minecraftProvider, Path intermediaryTiny) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final IntermediateMappingsProvider intermediateProvider = extension.getIntermediateMappingsProvider();
// When merging legacy versions there will be multiple named namespaces, so use intermediary as the common src ns
// Newer versions will use intermediary as the src ns
final String expectedSrcNs = minecraftProvider.isLegacyVersion()
? MappingsNamespace.INTERMEDIARY.toString() // <1.3
: MappingsNamespace.OFFICIAL.toString(); // >=1.3
return new IntermediateMappingsService(intermediaryTiny, expectedSrcNs);
return TYPE.create(project, options -> {
options.getIntermediaryTiny().set(intermediaryTiny.toFile());
options.getExpectedSrcNs().set(expectedSrcNs);
options.getMinecraftVersion().set(intermediateProvider.getMinecraftVersion());
});
}
private MemoryMappingTree createMemoryMappingTree() {
return createMemoryMappingTree(getIntermediaryTiny(), getOptions().getExpectedSrcNs().get());
}
@VisibleForTesting
public static MemoryMappingTree createMemoryMappingTree(Path mappingFile, String expectedSrcNs) {
final MemoryMappingTree tree = new MemoryMappingTree();
try {
MappingNsCompleter nsCompleter = new MappingNsCompleter(tree, Collections.singletonMap(MappingsNamespace.NAMED.toString(), MappingsNamespace.INTERMEDIARY.toString()), true);
try (BufferedReader reader = Files.newBufferedReader(getIntermediaryTiny(), StandardCharsets.UTF_8)) {
try (BufferedReader reader = Files.newBufferedReader(mappingFile, StandardCharsets.UTF_8)) {
Tiny2FileReader.read(reader, nsCompleter);
}
} catch (IOException e) {
@@ -120,6 +144,6 @@ public final class IntermediateMappingsService implements SharedService {
}
public Path getIntermediaryTiny() {
return Objects.requireNonNull(intermediaryTiny, "Intermediary mappings have not been setup");
return getOptions().getIntermediaryTiny().get().getAsFile().toPath();
}
}

View File

@@ -47,9 +47,15 @@ import com.google.common.base.Stopwatch;
import com.google.common.base.Supplier;
import com.google.gson.JsonObject;
import dev.architectury.loom.util.MappingOption;
import dev.architectury.loom.util.MappingOption;
import net.fabricmc.loom.util.service.ServiceFactory;
import org.apache.tools.ant.util.StringUtils;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.provider.Provider;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.Opcodes;
import org.slf4j.Logger;
@@ -68,8 +74,7 @@ import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.DeletingFileVisitor;
import net.fabricmc.loom.util.FileSystemUtil;
import net.fabricmc.loom.util.ZipUtils;
import net.fabricmc.loom.util.service.ScopedSharedServiceManager;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.loom.util.srg.ForgeMappingsMerger;
import net.fabricmc.loom.util.srg.MCPReader;
import net.fabricmc.loom.util.srg.SrgNamedWriter;
@@ -119,7 +124,7 @@ public class MappingConfiguration {
this.mappingOptions.put(MappingOption.DEFAULT, () -> this.tinyMappings);
}
public static MappingConfiguration create(Project project, SharedServiceManager serviceManager, DependencyInfo dependency, MinecraftProvider minecraftProvider) {
public static MappingConfiguration create(Project project, ServiceFactory serviceFactory, DependencyInfo dependency, MinecraftProvider minecraftProvider) {
final String version = dependency.getResolvedVersion();
final Path inputJar = dependency.resolveFile().orElseThrow(() -> new RuntimeException("Could not resolve mappings: " + dependency)).toPath();
final String mappingsName = StringUtils.removeSuffix(dependency.getDependency().getGroup() + "." + dependency.getDependency().getName(), "-unmerged");
@@ -146,29 +151,25 @@ public class MappingConfiguration {
final Path workingDir = minecraftProvider.dir(mappingsIdentifier).toPath();
MappingConfiguration mappingConfiguration;
MappingConfiguration mappingProvider;
if (extension.isForgeLike()) {
mappingConfiguration = new ForgeMigratedMappingConfiguration(mappingsIdentifier, workingDir);
mappingProvider = new ForgeMigratedMappingConfiguration(mappingsIdentifier, workingDir);
} else {
mappingConfiguration = new MappingConfiguration(mappingsIdentifier, workingDir);
mappingProvider = new MappingConfiguration(mappingsIdentifier, workingDir);
}
try {
mappingConfiguration.setup(project, serviceManager, minecraftProvider, inputJar);
mappingProvider.setup(project, serviceFactory, minecraftProvider, inputJar);
} catch (IOException e) {
cleanWorkingDirectory(workingDir);
throw new UncheckedIOException("Failed to setup mappings: " + dependency.getDepString(), e);
}
return mappingConfiguration;
return mappingProvider;
}
public TinyMappingsService getMappingsService(SharedServiceManager serviceManager) {
return getMappingsService(serviceManager, MappingOption.DEFAULT);
}
public TinyMappingsService getMappingsService(SharedServiceManager serviceManager, MappingOption mappingOption) {
public Path getMappingsPath(MappingOption mappingOption) {
Supplier<Path> mappingsSupplier = this.mappingOptions.get(mappingOption);
if (mappingsSupplier == null) {
@@ -177,16 +178,32 @@ public class MappingConfiguration {
throw new UnsupportedOperationException("Mapping option " + mappingOption + " found but file does not exist!");
}
return TinyMappingsService.create(serviceManager, Objects.requireNonNull(mappingsSupplier.get()));
return Objects.requireNonNull(mappingsSupplier.get());
}
protected void setup(Project project, SharedServiceManager serviceManager, MinecraftProvider minecraftProvider, Path inputJar) throws IOException {
public Provider<TinyMappingsService.Options> getMappingsServiceOptions(Project project) {
return getMappingsServiceOptions(project, MappingOption.DEFAULT);
}
public Provider<TinyMappingsService.Options> getMappingsServiceOptions(Project project, MappingOption mappingOption) {
return TinyMappingsService.createOptions(project, Objects.requireNonNull(getMappingsPath(mappingOption)));
}
public TinyMappingsService getMappingsService(Project project, ServiceFactory serviceFactory) {
return serviceFactory.get(getMappingsServiceOptions(project));
}
public TinyMappingsService getMappingsService(Project project, ServiceFactory serviceFactory, MappingOption mappingOption) {
return serviceFactory.get(getMappingsServiceOptions(project, mappingOption));
}
protected void setup(Project project, ServiceFactory serviceFactory, MinecraftProvider minecraftProvider, Path inputJar) throws IOException {
if (minecraftProvider.refreshDeps()) {
cleanWorkingDirectory(mappingsWorkingDir);
}
if (Files.notExists(tinyMappings) || minecraftProvider.refreshDeps()) {
storeMappings(project, serviceManager, minecraftProvider, inputJar);
storeMappings(project, serviceFactory, minecraftProvider, inputJar);
} else {
try (FileSystemUtil.Delegate fileSystem = FileSystemUtil.getJarFileSystem(inputJar, false)) {
extractExtras(fileSystem.get());
@@ -318,12 +335,12 @@ public class MappingConfiguration {
return isV2 ? "-v2" : "";
}
private void storeMappings(Project project, SharedServiceManager serviceManager, MinecraftProvider minecraftProvider, Path inputJar) throws IOException {
private void storeMappings(Project project, ServiceFactory serviceFactory, MinecraftProvider minecraftProvider, Path inputJar) throws IOException {
LOGGER.info(":extracting " + inputJar.getFileName());
if (isMCP(inputJar)) {
try {
readAndMergeMCP(project, serviceManager, minecraftProvider, inputJar);
readAndMergeMCP(project, serviceFactory, minecraftProvider, inputJar);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -338,7 +355,7 @@ public class MappingConfiguration {
if (areMappingsV2(baseTinyMappings)) {
// These are unmerged v2 mappings
IntermediateMappingsService intermediateMappingsService = IntermediateMappingsService.getInstance(serviceManager, project, minecraftProvider);
IntermediateMappingsService intermediateMappingsService = serviceFactory.get(IntermediateMappingsService.createOptions(project, minecraftProvider));
MappingsMerger.mergeAndSaveMappings(baseTinyMappings, tinyMappings, minecraftProvider, intermediateMappingsService);
} else {
@@ -365,7 +382,7 @@ public class MappingConfiguration {
}
}
private void readAndMergeMCP(Project project, SharedServiceManager serviceManager, MinecraftProvider minecraftProvider, Path mcpJar) throws Exception {
private void readAndMergeMCP(Project project, ServiceFactory serviceFactory, MinecraftProvider minecraftProvider, Path mcpJar) throws Exception {
LoomGradleExtension extension = LoomGradleExtension.get(project);
IntermediateMappingsService intermediateMappingsService = IntermediateMappingsService.getInstance(serviceManager, project, minecraftProvider);
Path intermediaryTinyPath = intermediateMappingsService.getIntermediaryTiny();

View File

@@ -27,29 +27,47 @@ package net.fabricmc.loom.configuration.providers.mappings;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.function.Supplier;
import net.fabricmc.loom.util.service.SharedService;
import net.fabricmc.loom.util.service.SharedServiceManager;
import com.google.common.base.Suppliers;
import org.gradle.api.Project;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.InputFile;
import net.fabricmc.loom.util.service.Service;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.loom.util.service.ServiceType;
import net.fabricmc.mappingio.MappingReader;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
public final class TinyMappingsService implements SharedService {
private final MemoryMappingTree mappingTree;
public final class TinyMappingsService extends Service<TinyMappingsService.Options> {
public static final ServiceType<Options, TinyMappingsService> TYPE = new ServiceType<>(Options.class, TinyMappingsService.class);
public TinyMappingsService(Path tinyMappings) {
public interface Options extends Service.Options {
@InputFile
RegularFileProperty getMappings();
}
public static Provider<Options> createOptions(Project project, Path mappings) {
return TYPE.create(project, options -> options.getMappings().set(project.file(mappings)));
}
public TinyMappingsService(Options options, ServiceFactory serviceFactory) {
super(options, serviceFactory);
}
private final Supplier<MemoryMappingTree> mappingTree = Suppliers.memoize(() -> {
try {
this.mappingTree = new MemoryMappingTree();
MappingReader.read(tinyMappings, mappingTree);
MemoryMappingTree mappingTree = new MemoryMappingTree();
MappingReader.read(getOptions().getMappings().get().getAsFile().toPath(), mappingTree);
return mappingTree;
} catch (IOException e) {
throw new UncheckedIOException("Failed to read mappings", e);
}
}
public static synchronized TinyMappingsService create(SharedServiceManager serviceManager, Path tinyMappings) {
return serviceManager.getOrCreateService("TinyMappingsService:" + tinyMappings.toAbsolutePath(), () -> new TinyMappingsService(tinyMappings));
}
});
public MemoryMappingTree getMappingTree() {
return mappingTree;
return mappingTree.get();
}
}

View File

@@ -37,7 +37,7 @@ import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.TinyRemapperHelper;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.tinyremapper.TinyRemapper;
import net.fabricmc.tinyremapper.api.TrClass;
@@ -56,7 +56,7 @@ public record SignatureFixerApplyVisitor(Map<String, String> signatureFixes) imp
};
}
public static Map<String, String> getRemappedSignatures(boolean toIntermediary, MappingConfiguration mappingConfiguration, Project project, SharedServiceManager serviceManager, String targetNamespace) throws IOException {
public static Map<String, String> getRemappedSignatures(boolean toIntermediary, MappingConfiguration mappingConfiguration, Project project, ServiceFactory serviceFactory, String targetNamespace) throws IOException {
if (mappingConfiguration.getSignatureFixes() == null) {
// No fixes
return Collections.emptyMap();
@@ -69,7 +69,7 @@ public record SignatureFixerApplyVisitor(Map<String, String> signatureFixes) imp
// Remap the sig fixes from intermediary to the target namespace
final Map<String, String> remapped = new HashMap<>();
final TinyRemapper sigTinyRemapper = TinyRemapperHelper.getTinyRemapper(project, serviceManager, MappingsNamespace.INTERMEDIARY.toString(), targetNamespace);
final TinyRemapper sigTinyRemapper = TinyRemapperHelper.getTinyRemapper(project, serviceFactory, MappingsNamespace.INTERMEDIARY.toString(), targetNamespace);
final Remapper sigAsmRemapper = sigTinyRemapper.getEnvironment().getRemapper();
// Remap the class names and the signatures using a new tiny remapper instance.

View File

@@ -56,7 +56,6 @@ import net.fabricmc.loom.configuration.providers.minecraft.SignatureFixerApplyVi
import net.fabricmc.loom.extension.LoomFiles;
import net.fabricmc.loom.util.SidedClassVisitor;
import net.fabricmc.loom.util.TinyRemapperHelper;
import net.fabricmc.loom.util.service.ScopedSharedServiceManager;
import net.fabricmc.loom.util.srg.InnerClassRemapper;
import net.fabricmc.loom.util.srg.RemapObjectHolderVisitor;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
@@ -206,11 +205,11 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
Files.deleteIfExists(remappedJars.outputJarPath());
final Set<String> classNames = extension.isForgeLike() ? InnerClassRemapper.readClassNames(remappedJars.inputJar()) : Set.of();
final Map<String, String> remappedSignatures = SignatureFixerApplyVisitor.getRemappedSignatures(getTargetNamespace() == MappingsNamespace.INTERMEDIARY, mappingConfiguration, getProject(), configContext.serviceManager(), toM);
final Map<String, String> remappedSignatures = SignatureFixerApplyVisitor.getRemappedSignatures(getTargetNamespace() == MappingsNamespace.INTERMEDIARY, mappingConfiguration, getProject(), configContext.serviceFactory(), toM);
final MinecraftVersionMeta.JavaVersion javaVersion = minecraftProvider.getVersionInfo().javaVersion();
final boolean fixRecords = javaVersion != null && javaVersion.majorVersion() >= 16;
TinyRemapper remapper = TinyRemapperHelper.getTinyRemapper(getProject(), configContext.serviceManager(), fromM, toM, fixRecords, (builder) -> {
TinyRemapper remapper = TinyRemapperHelper.getTinyRemapper(getProject(), configContext.serviceFactory(), fromM, toM, fixRecords, (builder) -> {
builder.extraPostApplyVisitor(new SignatureFixerApplyVisitor(remappedSignatures));
if (extension.isNeoForge()) builder.extension(new MixinExtension(inputTag -> true));
configureRemapper(remappedJars, builder);
@@ -234,21 +233,19 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
getMavenHelper(remappedJars.type()).savePom();
if (extension.isForgeLikeAndOfficial()) {
try (var serviceManager = new ScopedSharedServiceManager()) {
final MappingOption mappingOption = MappingOption.forPlatform(extension);
final TinyMappingsService mappingsService = extension.getMappingConfiguration().getMappingsService(serviceManager, mappingOption);
final String className;
final MappingOption mappingOption = MappingOption.forPlatform(extension);
final TinyMappingsService mappingsService = extension.getMappingConfiguration().getMappingsService(project, configContext.serviceFactory(), mappingOption);
final String className;
if (extension.isNeoForge()) {
className = "net.neoforged.neoforge.registries.ObjectHolderRegistry";
} else {
className = "net.minecraftforge.registries.ObjectHolderRegistry";
}
final String sourceNamespace = IntermediaryNamespaces.runtimeIntermediary(project);
final MemoryMappingTree mappings = mappingsService.getMappingTree();
RemapObjectHolderVisitor.remapObjectHolder(remappedJars.outputJar().getPath(), className, mappings, sourceNamespace, "named");
if (extension.isNeoForge()) {
className = "net.neoforged.neoforge.registries.ObjectHolderRegistry";
} else {
className = "net.minecraftforge.registries.ObjectHolderRegistry";
}
final String sourceNamespace = IntermediaryNamespaces.runtimeIntermediary(project);
final MemoryMappingTree mappings = mappingsService.getMappingTree();
RemapObjectHolderVisitor.remapObjectHolder(remappedJars.outputJar().getPath(), className, mappings, sourceNamespace, "named");
}
}

View File

@@ -46,8 +46,8 @@ import org.apache.commons.io.output.NullOutputStream;
import org.cadixdev.lorenz.MappingSet;
import org.cadixdev.mercury.Mercury;
import org.cadixdev.mercury.remapper.MercuryRemapper;
import org.jetbrains.annotations.Nullable;
import org.gradle.api.Project;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
@@ -63,12 +63,11 @@ import net.fabricmc.loom.util.SourceRemapper;
import net.fabricmc.loom.util.ThreadingUtils;
import net.fabricmc.loom.util.TinyRemapperHelper;
import net.fabricmc.loom.util.ZipUtils;
import net.fabricmc.loom.util.service.ScopedSharedServiceManager;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.lorenztiny.TinyMappingsReader;
public class ForgeSourcesRemapper {
public static void addBaseForgeSources(Project project) throws IOException {
public static void addBaseForgeSources(Project project, ServiceFactory serviceFactory) throws IOException {
List<Path> minecraftJars = LoomGradleExtension.get(project).getMinecraftJars(MappingsNamespace.NAMED);
Path minecraftJar;
@@ -85,18 +84,16 @@ public class ForgeSourcesRemapper {
Path sourcesJar = GenerateSourcesTask.getJarFileWithSuffix("-sources.jar", minecraftJar).toPath();
if (!Files.exists(sourcesJar)) {
try (var serviceManager = new ScopedSharedServiceManager()) {
addForgeSources(project, serviceManager, minecraftJar, sourcesJar);
}
addForgeSources(project, serviceFactory, minecraftJar, sourcesJar);
}
}
public static void addForgeSources(Project project, SharedServiceManager serviceManager, @Nullable Path inputJar, Path sourcesJar) throws IOException {
public static void addForgeSources(Project project, ServiceFactory serviceFactory, @Nullable Path inputJar, Path sourcesJar) throws IOException {
try (FileSystemUtil.Delegate inputFs = inputJar == null ? null : FileSystemUtil.getJarFileSystem(inputJar, true);
FileSystemUtil.Delegate outputFs = FileSystemUtil.getJarFileSystem(sourcesJar, true)) {
ThreadingUtils.TaskCompleter taskCompleter = ThreadingUtils.taskCompleter();
provideForgeSources(project, serviceManager, path -> {
provideForgeSources(project, serviceFactory, path -> {
Path inputPath = inputFs == null ? null : inputFs.get().getPath(path.replace(".java", ".class"));
if (inputPath != null && Files.notExists(inputPath)) {
@@ -126,7 +123,7 @@ public class ForgeSourcesRemapper {
}
}
public static void provideForgeSources(Project project, SharedServiceManager serviceManager, Predicate<String> classFilter, BiConsumer<String, byte[]> consumer) throws IOException {
public static void provideForgeSources(Project project, ServiceFactory serviceFactory, Predicate<String> classFilter, BiConsumer<String, byte[]> consumer) throws IOException {
LoomGradleExtension extension = LoomGradleExtension.get(project);
String sourceDependency = extension.getForgeUserdevProvider().getConfig().sources();
List<Path> forgeInstallerSources = new ArrayList<>();
@@ -140,11 +137,11 @@ public class ForgeSourcesRemapper {
Map<String, byte[]> forgeSources = extractSources(forgeInstallerSources);
forgeSources.keySet().removeIf(classFilter.negate());
project.getLogger().lifecycle(":extracted {} forge source classes", forgeSources.size());
remapSources(project, serviceManager, forgeSources);
remapSources(project, serviceFactory, forgeSources);
forgeSources.forEach(consumer);
}
private static void remapSources(Project project, SharedServiceManager serviceManager, Map<String, byte[]> sources) throws IOException {
private static void remapSources(Project project, ServiceFactory serviceFactory, Map<String, byte[]> sources) throws IOException {
File tmpInput = File.createTempFile("tmpInputForgeSources", null);
tmpInput.delete();
tmpInput.deleteOnExit();
@@ -178,7 +175,7 @@ public class ForgeSourcesRemapper {
System.setErr(new PrintStream(NullOutputStream.NULL_OUTPUT_STREAM));
}
remapForgeSourcesInner(project, serviceManager, tmpInput.toPath(), tmpOutput.toPath());
remapForgeSourcesInner(project, serviceFactory, tmpInput.toPath(), tmpOutput.toPath());
if (!ForgeToolExecutor.shouldShowVerboseStderr(project)) {
System.setOut(out);
@@ -215,13 +212,13 @@ public class ForgeSourcesRemapper {
}
}
private static void remapForgeSourcesInner(Project project, SharedServiceManager serviceManager, Path tmpInput, Path tmpOutput) throws IOException {
private static void remapForgeSourcesInner(Project project, ServiceFactory serviceFactory, Path tmpInput, Path tmpOutput) throws IOException {
LoomGradleExtension extension = LoomGradleExtension.get(project);
Mercury mercury = SourceRemapper.createMercuryWithClassPath(project, false);
final MappingOption mappingOption = MappingOption.forPlatform(extension);
final String sourceNamespace = IntermediaryNamespaces.intermediary(project);
TinyMappingsService mappingsService = extension.getMappingConfiguration().getMappingsService(serviceManager, mappingOption);
TinyMappingsService mappingsService = extension.getMappingConfiguration().getMappingsService(project, serviceFactory, mappingOption);
MappingSet mappings = new TinyMappingsReader(mappingsService.getMappingTree(), sourceNamespace, "named").read();
for (Map.Entry<String, String> entry : TinyRemapperHelper.JSR_TO_JETBRAINS.entrySet()) {

View File

@@ -484,7 +484,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
holder = objectFactory.newInstance(RemapperExtensionHolder.class, RemapperParameters.None.INSTANCE);
}
holder.getRemapperExtensionClass().set(remapperExtensionClass);
holder.getRemapperExtensionClass().set(remapperExtensionClass.getName());
remapperExtensions.add(holder);
}

View File

@@ -24,12 +24,12 @@
package net.fabricmc.loom.extension;
import java.lang.reflect.Constructor;
import javax.inject.Inject;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.Optional;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.ClassVisitor;
@@ -43,25 +43,19 @@ import net.fabricmc.tinyremapper.TinyRemapper;
import net.fabricmc.tinyremapper.api.TrClass;
public abstract class RemapperExtensionHolder {
// Null when RemapperParameters.None.class
private final RemapperParameters remapperParameters;
@Inject
public RemapperExtensionHolder(RemapperParameters remapperParameters) {
this.remapperParameters = remapperParameters;
this.getRemapperParameters().set(remapperParameters);
}
@Input
public abstract Property<Class<? extends RemapperExtension<?>>> getRemapperExtensionClass();
public abstract Property<String> getRemapperExtensionClass();
@Nested
@Optional
public RemapperParameters getRemapperParameters() {
return remapperParameters;
}
public abstract Property<RemapperParameters> getRemapperParameters();
public void apply(TinyRemapper.Builder tinyRemapperBuilder, String sourceNamespace, String targetNamespace, ObjectFactory objectFactory) {
final RemapperExtension<?> remapperExtension = newInstance(objectFactory);
public void apply(TinyRemapper.Builder tinyRemapperBuilder, String sourceNamespace, String targetNamespace) {
final RemapperExtension<?> remapperExtension = newInstance();
tinyRemapperBuilder.extraPostApplyVisitor(new RemapperExtensionImpl(remapperExtension, sourceNamespace, targetNamespace));
@@ -86,20 +80,41 @@ public abstract class RemapperExtensionHolder {
}
}
private RemapperExtension<?> newInstance(ObjectFactory objectFactory) {
private RemapperExtension<?> newInstance() {
try {
Class<? extends RemapperExtension<?>> remapperExtensionClass = getRemapperExtensionClass().get();
//noinspection unchecked
final Class<? extends RemapperExtension<?>> remapperExtensionClass = (Class<? extends RemapperExtension<?>>) Class.forName(getRemapperExtensionClass().get());
final Constructor<?> constructor = getInjectedConstructor(remapperExtensionClass);
if (remapperParameters == RemapperParameters.None.INSTANCE) {
return objectFactory.newInstance(remapperExtensionClass);
if (getRemapperParameters().get() instanceof RemapperParameters.None) {
return (RemapperExtension<?>) constructor.newInstance();
}
return objectFactory.newInstance(remapperExtensionClass, remapperParameters);
return (RemapperExtension<?>) constructor.newInstance(getRemapperParameters().get());
} catch (Exception e) {
throw new RuntimeException("Failed to create remapper extension", e);
throw new RuntimeException("Failed to create remapper extension for class: " + getRemapperExtensionClass().get(), e);
}
}
private static Constructor<?> getInjectedConstructor(Class<?> clazz) {
Constructor<?>[] constructors = clazz.getConstructors();
Constructor<?> injectedConstructor = null;
for (Constructor<?> constructor : constructors) {
if (injectedConstructor != null) {
throw new RuntimeException("RemapperExtension class " + clazz.getName() + " has more than one constructor");
}
injectedConstructor = constructor;
}
if (injectedConstructor == null) {
throw new RuntimeException("RemapperExtension class " + clazz.getName() + " does not have a constructor");
}
return injectedConstructor;
}
private static final class RemapperExtensionImpl implements TinyRemapper.ApplyVisitorProvider {
private final RemapperExtension<?> remapperExtension;
private final String sourceNamespace;

View File

@@ -230,7 +230,7 @@ public abstract class AbstractRemapJarTask extends Jar {
return getInputFile();
}
protected static List<String> getRootPaths(Set<File> files) {
public static List<String> getRootPaths(Set<File> files) {
return files.stream()
.map(root -> {
String rootPath = root.getAbsolutePath().replace("\\", "/");
@@ -243,7 +243,7 @@ public abstract class AbstractRemapJarTask extends Jar {
}).toList();
}
protected static Function<File, String> relativePath(List<String> rootPaths) {
public static Function<File, String> relativePath(List<String> rootPaths) {
return file -> {
String s = file.getAbsolutePath().replace("\\", "/");

View File

@@ -109,7 +109,7 @@ import net.fabricmc.loom.util.gradle.ThreadedSimpleProgressLogger;
import net.fabricmc.loom.util.gradle.WorkerDaemonClientsManagerHelper;
import net.fabricmc.loom.util.ipc.IPCClient;
import net.fabricmc.loom.util.ipc.IPCServer;
import net.fabricmc.loom.util.service.ScopedSharedServiceManager;
import net.fabricmc.loom.util.service.ScopedServiceFactory;
import net.fabricmc.mappingio.MappingReader;
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
import net.fabricmc.mappingio.format.tiny.Tiny2FileWriter;
@@ -509,8 +509,8 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
private MinecraftJar rebuildInputJar() {
final List<MinecraftJar> minecraftJars;
try (var serviceManager = new ScopedSharedServiceManager()) {
final var configContext = new ConfigContextImpl(getProject(), serviceManager, getExtension());
try (var serviceFactory = new ScopedServiceFactory()) {
final var configContext = new ConfigContextImpl(getProject(), serviceFactory, getExtension());
final var provideContext = new AbstractMappedMinecraftProvider.ProvideContext(false, true, configContext);
minecraftJars = getExtension().getNamedMinecraftProvider().provide(provideContext);
} catch (Exception e) {
@@ -764,9 +764,11 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
if (minecraftJarProcessorManager != null) {
mappingsProcessors.add(mappings -> {
try (var serviceManager = new ScopedSharedServiceManager()) {
final var configContext = new ConfigContextImpl(getProject(), serviceManager, getExtension());
try (var serviceFactory = new ScopedServiceFactory()) {
final var configContext = new ConfigContextImpl(getProject(), serviceFactory, getExtension());
return minecraftJarProcessorManager.processMappings(mappings, new MappingProcessorContextImpl(configContext));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
}

View File

@@ -57,7 +57,7 @@ import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
import net.fabricmc.loom.util.FileSystemUtil;
import net.fabricmc.loom.util.SourceRemapper;
import net.fabricmc.loom.util.service.ScopedSharedServiceManager;
import net.fabricmc.loom.util.service.ScopedServiceFactory;
import net.fabricmc.lorenztiny.TinyMappingsJoiner;
import net.fabricmc.mappingio.MappingReader;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
@@ -110,8 +110,8 @@ public abstract class MigrateMappingsTask extends AbstractLoomTask {
File mappings = loadMappings();
MappingConfiguration mappingConfiguration = extension.getMappingConfiguration();
try (var serviceManager = new ScopedSharedServiceManager()) {
MemoryMappingTree currentMappings = mappingConfiguration.getMappingsService(serviceManager).getMappingTree();
try (var serviceFactory = new ScopedServiceFactory()) {
MemoryMappingTree currentMappings = mappingConfiguration.getMappingsService(project, serviceFactory).getMappingTree();
MemoryMappingTree targetMappings = getMappings(mappings);
migrateMappings(project, extension, inputDir, outputDir, currentMappings, targetMappings);
project.getLogger().lifecycle(":remapped project written to " + outputDir.toAbsolutePath());

View File

@@ -25,18 +25,14 @@
package net.fabricmc.loom.task;
import java.io.IOException;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.inject.Inject;
@@ -50,11 +46,10 @@ import org.gradle.api.file.RegularFileProperty;
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.provider.SetProperty;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.TaskProvider;
@@ -71,8 +66,8 @@ import net.fabricmc.loom.build.nesting.JarNester;
import net.fabricmc.loom.build.nesting.NestableJarGenerationTask;
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
import net.fabricmc.loom.configuration.mods.ArtifactMetadata;
import net.fabricmc.loom.extension.MixinExtension;
import net.fabricmc.loom.task.service.MappingsService;
import net.fabricmc.loom.task.service.MixinRefmapService;
import net.fabricmc.loom.task.service.TinyRemapperService;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.ExceptionUtil;
@@ -80,11 +75,10 @@ import net.fabricmc.loom.util.ModPlatform;
import net.fabricmc.loom.util.Pair;
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.fmj.FabricModJsonUtils;
import net.fabricmc.loom.util.service.BuildSharedServiceManager;
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
import net.fabricmc.loom.util.service.ScopedServiceFactory;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.tinyremapper.OutputConsumerPath;
import net.fabricmc.tinyremapper.TinyRemapper;
@@ -137,13 +131,14 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
@Input
@ApiStatus.Internal
public abstract Property<Boolean> getUseMixinAP();
private final Provider<BuildSharedServiceManager> serviceManagerProvider;
@Nested
public abstract Property<TinyRemapperService.Options> getTinyRemapperServiceOptions();
@Nested
public abstract ListProperty<MixinRefmapService.Options> getMixinRefmapServiceOptions();
@Inject
public RemapJarTask() {
super();
serviceManagerProvider = BuildSharedServiceManager.createForTask(this, getBuildEventsListenerRegistry());
final ConfigurationContainer configurations = getProject().getConfigurations();
getClasspath().from(configurations.getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME));
getAddNestedDependencies().convention(true).finalizeValueOnRead();
@@ -162,6 +157,9 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
setPreserveFileTimestamps(false);
getJarType().set("classes");
getTinyRemapperServiceOptions().set(TinyRemapperService.createOptions(this));
getMixinRefmapServiceOptions().set(MixinRefmapService.createOptions(this));
}
@TaskAction
@@ -174,16 +172,14 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
}
if (!params.namespacesMatch()) {
params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(getTinyRemapperService()));
params.getTinyRemapperServiceOptions().set(getTinyRemapperServiceOptions());
params.getMixinRefmapServiceOptions().set(getMixinRefmapServiceOptions());
params.getRemapClasspath().from(getClasspath());
final boolean mixinAp = getUseMixinAP().get();
params.getUseMixinExtension().set(!mixinAp);
if (mixinAp) {
setupLegacyMixinRefmapRemapping(params);
}
// Add the mixin refmap remap type to the manifest
// This is used by the mod dependency remapper to determine if it should remap the refmap
// or if the refmap should be remapped by mixin at runtime.
@@ -199,56 +195,17 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
params.getInjectAccessWidener().set(extension.getAccessWidenerPath());
}
params.getMappingBuildServiceUuid().convention("this should be unavailable!");
params.getReadMixinConfigsFromManifest().set(getReadMixinConfigsFromManifest());
params.getAtAccessWideners().set(getAtAccessWideners());
if (!getAtAccessWideners().get().isEmpty()) {
params.getMappingBuildServiceUuid().set(UnsafeWorkQueueHelper.create(MappingsService.createDefault(getProject(), serviceManagerProvider.get().get(), getSourceNamespace().get(), getTargetNamespace().get())));
params.getMappingsServiceOptions().set(MappingsService.createOptionsWithProjectMappings(getProject(), getSourceNamespace(), getTargetNamespace()));
}
params.getOptimizeFmj().set(getOptimizeFabricModJson().get());
});
}
private void setupLegacyMixinRefmapRemapping(RemapParams params) {
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
final MixinExtension mixinExtension = extension.getMixin();
final Collection<String> allMixinConfigs = new LinkedHashSet<>();
final FabricModJson fabricModJson = FabricModJsonFactory.createFromZipNullable(getInputFile().getAsFile().get().toPath());
if (fabricModJson != null) {
allMixinConfigs.addAll(fabricModJson.getMixinConfigurations());
}
if (getReadMixinConfigsFromManifest().get()) {
allMixinConfigs.addAll(ModBuildExtensions.readMixinConfigsFromManifest(getInputFile().get().getAsFile()));
}
if (allMixinConfigs.isEmpty()) {
return;
}
for (SourceSet sourceSet : mixinExtension.getMixinSourceSets()) {
MixinExtension.MixinInformationContainer container = Objects.requireNonNull(
MixinExtension.getMixinInformationContainer(sourceSet)
);
final List<String> rootPaths = getRootPaths(sourceSet.getResources().getSrcDirs());
final String refmapName = container.refmapNameProvider().get();
final List<String> mixinConfigs = container.sourceSet().getResources()
.matching(container.mixinConfigPattern())
.getFiles()
.stream()
.map(relativePath(rootPaths))
.filter(allMixinConfigs::contains)
.toList();
params.getMixinData().add(new RemapParams.RefmapData(mixinConfigs, refmapName));
}
}
public interface RemapParams extends AbstractRemapParams {
ConfigurableFileCollection getNestedJars();
@@ -257,36 +214,35 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
Property<ModPlatform> getPlatform();
RegularFileProperty getInjectAccessWidener();
Property<Boolean> getReadMixinConfigsFromManifest();
SetProperty<String> getAtAccessWideners();
Property<Boolean> getUseMixinExtension();
Property<Boolean> getOptimizeFmj();
record RefmapData(List<String> mixinConfigs, String refmapName) implements Serializable { }
ListProperty<RefmapData> getMixinData();
Property<String> getTinyRemapperBuildServiceUuid();
Property<String> getMappingBuildServiceUuid();
Property<TinyRemapperService.Options> getTinyRemapperServiceOptions();
ListProperty<MixinRefmapService.Options> getMixinRefmapServiceOptions();
Property<MappingsService.Options> getMappingsServiceOptions();
}
public abstract static class RemapAction extends AbstractRemapAction<RemapParams> {
private static final Logger LOGGER = LoggerFactory.getLogger(RemapAction.class);
private final @Nullable TinyRemapperService tinyRemapperService;
private @Nullable TinyRemapperService tinyRemapperService;
private @Nullable TinyRemapper tinyRemapper;
public RemapAction() {
this.tinyRemapperService = getParameters().getTinyRemapperBuildServiceUuid().isPresent()
? UnsafeWorkQueueHelper.get(getParameters().getTinyRemapperBuildServiceUuid(), TinyRemapperService.class)
: null;
}
@Override
public void execute() {
try {
try (var serviceFactory = new ScopedServiceFactory()) {
LOGGER.info("Remapping {} to {}", inputFile, outputFile);
this.tinyRemapperService = getParameters().getTinyRemapperServiceOptions().isPresent()
? serviceFactory.get(getParameters().getTinyRemapperServiceOptions().get())
: null;
prepare();
if (tinyRemapperService != null) {
@@ -305,9 +261,9 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
remapAccessWidener();
}
addRefmaps();
addRefmaps(serviceFactory);
addNestedJars();
ModBuildExtensions.convertAwToAt(getParameters().getAtAccessWideners(), outputFile, getParameters().getMappingBuildServiceUuid());
ModBuildExtensions.convertAwToAt(serviceFactory, getParameters().getAtAccessWideners(), outputFile, getParameters().getMappingsServiceOptions());
if (!getParameters().getPlatform().get().isForgeLike()) {
modifyJarManifest();
@@ -433,21 +389,14 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
JarNester.nestJars(nestedJars.getFiles(), outputFile.toFile(), getParameters().getPlatform().get(), LOGGER);
}
private void addRefmaps() throws IOException {
private void addRefmaps(ServiceFactory serviceFactory) throws IOException {
if (getParameters().getUseMixinExtension().getOrElse(false)) {
return;
}
for (RemapParams.RefmapData refmapData : getParameters().getMixinData().get()) {
if (ZipUtils.contains(outputFile, refmapData.refmapName())) {
int transformed = ZipUtils.transformJson(JsonObject.class, outputFile, refmapData.mixinConfigs().stream().collect(Collectors.toMap(s -> s, s -> json -> {
if (!json.has("refmap")) {
json.addProperty("refmap", refmapData.refmapName());
}
return json;
})));
}
for (MixinRefmapService.Options options : getParameters().getMixinRefmapServiceOptions().get()) {
MixinRefmapService mixinRefmapService = serviceFactory.get(options);
mixinRefmapService.applyToJar(outputFile, getParameters().getReadMixinConfigsFromManifest().get());
}
}
@@ -475,9 +424,4 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
.map(relativePath(rootPaths))
.toList();
}
@Internal
public TinyRemapperService getTinyRemapperService() {
return TinyRemapperService.getOrCreate(serviceManagerProvider.get().get(), this);
}
}

View File

@@ -40,7 +40,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.fabricmc.loom.task.service.SourceRemapperService;
import net.fabricmc.loom.util.newService.ScopedServiceFactory;
import net.fabricmc.loom.util.service.ScopedServiceFactory;
public abstract class RemapSourcesJarTask extends AbstractRemapJarTask {
@Nested

View File

@@ -56,7 +56,7 @@ public abstract class JarManifestService implements BuildService<JarManifestServ
Property<MixinVersion> getMixinVersion();
}
public static synchronized Provider<JarManifestService> get(Project project) {
public static Provider<JarManifestService> get(Project project) {
return project.getGradle().getSharedServices().registerIfAbsent("LoomJarManifestService:" + project.getName(), JarManifestService.class, spec -> {
spec.parameters(params -> {
LoomGradleExtension extension = LoomGradleExtension.get(project);

View File

@@ -26,53 +26,65 @@ package net.fabricmc.loom.task.service;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Objects;
import java.util.function.Supplier;
import dev.architectury.loom.util.MappingOption;
import com.google.common.base.Suppliers;
import org.cadixdev.lorenz.MappingSet;
import org.gradle.api.Project;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.Nested;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
import net.fabricmc.loom.util.service.SharedService;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.service.Service;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.loom.util.service.ServiceType;
import net.fabricmc.lorenztiny.TinyMappingsReader;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
public final class LorenzMappingService implements SharedService {
private MappingSet mappings;
public final class LorenzMappingService extends Service<LorenzMappingService.Options> {
public static final ServiceType<Options, LorenzMappingService> TYPE = new ServiceType<>(Options.class, LorenzMappingService.class);
public LorenzMappingService(MappingSet mappings) {
this.mappings = mappings;
public interface Options extends Service.Options {
@Nested
Property<MappingsService.Options> getMappings();
}
public static synchronized LorenzMappingService create(SharedServiceManager sharedServiceManager, MappingConfiguration mappingConfiguration, MappingsNamespace from, MappingsNamespace to) {
return sharedServiceManager.getOrCreateService(mappingConfiguration.getBuildServiceName("LorenzMappingService", from.toString(), to.toString()), () -> {
MappingOption mappingOption = MappingOption.DEFAULT;
public static Provider<Options> createOptions(Project project, MappingConfiguration mappingConfiguration, MappingsNamespace from, MappingsNamespace to) {
MappingOption mappingOption = from == MappingsNamespace.SRG || to == MappingsNamespace.SRG ? MappingOption.WITH_SRG
: from == MappingsNamespace.MOJANG || to == MappingsNamespace.MOJANG ? MappingOption.WITH_MOJANG : MappingOption.DEFAULT;
if (from == MappingsNamespace.SRG || to == MappingsNamespace.SRG) {
mappingOption = MappingOption.WITH_SRG;
} else if (from == MappingsNamespace.MOJANG || to == MappingsNamespace.MOJANG) {
mappingOption = MappingOption.WITH_MOJANG;
return TYPE.create(project, options -> options.getMappings().set(
MappingsService.createOptions(
project,
mappingConfiguration.getMappingsPath(mappingOption),
to.toString(),
from.toString(),
false)
));
}
private final Supplier<MappingSet> mappings = Suppliers.memoize(this::readMappings);
public LorenzMappingService(Options options, ServiceFactory serviceFactory) {
super(options, serviceFactory);
}
private MappingSet readMappings() {
MappingsService mappingsService = getServiceFactory().get(getOptions().getMappings().get());
try {
try (var reader = new TinyMappingsReader(mappingsService.getMemoryMappingTree(), mappingsService.getFrom(), mappingsService.getTo())) {
return reader.read();
}
MemoryMappingTree m = mappingConfiguration.getMappingsService(sharedServiceManager, mappingOption).getMappingTree();
try {
try (var reader = new TinyMappingsReader(m, from.toString(), to.toString())) {
return new LorenzMappingService(reader.read());
}
} catch (IOException e) {
throw new UncheckedIOException("Failed to read lorenz mappings", e);
}
});
} catch (IOException e) {
throw new UncheckedIOException("Failed to read lorenz mappings", e);
}
}
@Override
public void close() throws IOException {
this.mappings = null;
}
public MappingSet mappings() {
return Objects.requireNonNull(mappings);
public MappingSet getMappings() {
return mappings.get();
}
}

View File

@@ -24,83 +24,121 @@
package net.fabricmc.loom.task.service;
import java.io.Closeable;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import org.gradle.api.Project;
import org.gradle.api.file.RegularFileProperty;
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 net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
import net.fabricmc.loom.util.TinyRemapperHelper;
import net.fabricmc.loom.util.service.SharedService;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.service.Service;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.loom.util.service.ServiceType;
import net.fabricmc.mappingio.MappingReader;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
import net.fabricmc.tinyremapper.IMappingProvider;
public final class MappingsService implements SharedService {
private record Options(Path mappingsFile, String from, String to, boolean remapLocals) { }
/**
* A service that provides mappings for remapping.
*/
public final class MappingsService extends Service<MappingsService.Options> implements Closeable {
public static ServiceType<Options, MappingsService> TYPE = new ServiceType<>(Options.class, MappingsService.class);
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));
// TODO use a nested TinyMappingsService instead of duplicating it
public interface Options extends Service.Options {
@InputFile
RegularFileProperty getMappingsFile();
@Input
Property<String> getFrom();
@Input
Property<String> getTo();
@Input
Property<Boolean> getRemapLocals();
}
public static MappingsService createDefault(Project project, SharedServiceManager serviceManager, String from, String to) {
/**
* Returns options for creating a new mappings service, with a given mappings file.
*/
public static Provider<Options> createOptions(Project project, Path mappingsFile, String from, String to, boolean remapLocals) {
return createOptions(project, mappingsFile, project.provider(() -> from), project.provider(() -> to), remapLocals);
}
/**
* Returns options for creating a new mappings service, with a given mappings file.
*/
public static Provider<Options> createOptions(Project project, Path mappingsFile, Provider<String> from, Provider<String> to, boolean remapLocals) {
return TYPE.create(project, o -> {
o.getMappingsFile().set(mappingsFile.toFile());
o.getFrom().set(from);
o.getTo().set(to);
o.getRemapLocals().set(remapLocals);
});
}
/**
* Returns options for creating a new mappings service, using the mappings as specified in the project's mapping configuration.
*/
public static Provider<Options> createOptionsWithProjectMappings(Project project, Provider<String> from, Provider<String> to) {
final MappingConfiguration mappingConfiguration = LoomGradleExtension.get(project).getMappingConfiguration();
final String name = mappingConfiguration.getBuildServiceName("mappingsProvider", from, to);
return MappingsService.create(serviceManager, name, LoomGradleExtension.get(project).getPlatformMappingFile(), from, to, false);
return createOptions(project, LoomGradleExtension.get(project).getPlatformMappingFile(), from, to, false);
}
private final Options options;
public MappingsService(Options options) {
this.options = options;
public MappingsService(Options options, ServiceFactory serviceFactory) {
super(options, serviceFactory);
}
private IMappingProvider mappingProvider = null;
private MemoryMappingTree memoryMappingTree = null;
public synchronized IMappingProvider getMappingsProvider() {
public IMappingProvider getMappingsProvider() {
if (mappingProvider == null) {
try {
mappingProvider = TinyRemapperHelper.create(
options.mappingsFile(),
options.from(),
options.to(),
options.remapLocals()
getMappingsPath(),
getFrom(),
getTo(),
getOptions().getRemapLocals().get()
);
} catch (IOException e) {
throw new UncheckedIOException("Failed to read mappings from: " + options.mappingsFile(), e);
throw new UncheckedIOException("Failed to read mappings from: " + getMappingsPath(), e);
}
}
return mappingProvider;
}
public synchronized MemoryMappingTree getMemoryMappingTree() {
public MemoryMappingTree getMemoryMappingTree() {
if (memoryMappingTree == null) {
memoryMappingTree = new MemoryMappingTree();
try {
MappingReader.read(options.mappingsFile(), memoryMappingTree);
MappingReader.read(getMappingsPath(), memoryMappingTree);
} catch (IOException e) {
throw new UncheckedIOException("Failed to read mappings from: " + options.mappingsFile(), e);
throw new UncheckedIOException("Failed to read mappings from: " + getMappingsPath(), e);
}
}
return memoryMappingTree;
}
public String getFromNamespace() {
return options.from();
public String getFrom() {
return getOptions().getFrom().get();
}
public String getToNamespace() {
return options.to();
public String getTo() {
return getOptions().getTo().get();
}
public Path getMappingsPath() {
return getOptions().getMappingsFile().get().getAsFile().toPath();
}
@Override

View File

@@ -0,0 +1,203 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2024 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.task.service;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.file.ConfigurableFileCollection;
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.SourceSet;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.build.mixin.AnnotationProcessorInvoker;
import net.fabricmc.loom.util.TinyRemapperHelper;
import net.fabricmc.loom.util.gradle.GradleUtils;
import net.fabricmc.loom.util.gradle.SourceSetHelper;
import net.fabricmc.loom.util.service.Service;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.loom.util.service.ServiceType;
import net.fabricmc.tinyremapper.IMappingProvider;
public class MixinAPMappingService extends Service<MixinAPMappingService.Options> {
public static final ServiceType<Options, MixinAPMappingService> TYPE = new ServiceType<>(Options.class, MixinAPMappingService.class);
// TODO look into seeing if we can make this an option, it likely breaks project isolation.
private static final boolean INCLUDE_CROSS_PROJECT_MAPPINGS = true;
// Again look into what the result of changing this would be.
private static final boolean USE_ALL_SOURCE_SETS = true;
private static final Logger LOGGER = LoggerFactory.getLogger(MixinAPMappingService.class);
public interface Options extends Service.Options {
@InputFiles // We need to depend on all the outputs, as we don't know if the mixin mapping will exist at the time of task creation
ConfigurableFileCollection getCompileOutputs();
@Input
Property<String> getMixinMappingFileName();
@Input
Property<String> getFrom();
@Input
Property<String> getTo();
}
public static Provider<List<Options>> createOptions(Project thisProject, Provider<String> from, Provider<String> to) {
final LoomGradleExtension thisExtension = LoomGradleExtension.get(thisProject);
String mappingId = thisExtension.getMappingConfiguration().mappingsIdentifier;
var providers = new ArrayList<Provider<Options>>();
Consumer<Project> processProject = project -> {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
Collection<SourceSet> sourceSets = USE_ALL_SOURCE_SETS ? SourceSetHelper.getSourceSets(project) : extension.getMixin().getMixinSourceSets();
for (SourceSet sourceSet : sourceSets) {
LOGGER.debug("Creating MixinAPMappingService for source set: {}", sourceSet.getName());
var provider = createOptions(
thisProject,
sourceSet,
from,
to
);
if (provider != null) {
providers.add(provider);
} else {
LOGGER.debug("Failed to create MixinAPMappingService for source set: {}", sourceSet.getName());
}
}
};
if (!INCLUDE_CROSS_PROJECT_MAPPINGS) {
processProject.accept(thisProject);
} else {
GradleUtils.allLoomProjects(thisProject.getGradle(), project -> {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
if (!mappingId.equals(extension.getMappingConfiguration().mappingsIdentifier)) {
// Only find mixin mappings that are from other projects with the same mapping id.
return;
}
processProject.accept(project);
});
}
return thisProject.provider(() -> providers.stream().map(Provider::get).toList());
}
@Nullable
public static Provider<Options> createOptions(Project project, SourceSet sourceSet, Provider<String> from, Provider<String> to) {
final File mixinMappings = AnnotationProcessorInvoker.getMixinMappingsForSourceSet(project, sourceSet);
final Task compileTask = project.getTasks().findByName(sourceSet.getCompileJavaTaskName()); // TODO what about other languages?
if (compileTask == null) {
return null;
}
boolean containsOutput = false;
for (File file : compileTask.getOutputs().getFiles()) {
if (file.getName().equals(mixinMappings.getName())) {
containsOutput = true;
break;
}
}
if (!containsOutput) {
LOGGER.warn("Failed to find mixin mappings {} in task outputs: {}", mixinMappings.getName(), compileTask.getOutputs().getFiles());
return null;
}
return TYPE.create(project, o -> {
o.getCompileOutputs().from(compileTask.getOutputs());
o.getMixinMappingFileName().set(mixinMappings.getName());
o.getFrom().set(from);
o.getTo().set(to);
});
}
private IMappingProvider mappingProvider = null;
private boolean exists = true;
public MixinAPMappingService(Options options, ServiceFactory serviceFactory) {
super(options, serviceFactory);
}
@Nullable
public IMappingProvider getMappingsProvider() {
if (!exists) {
return null;
}
if (mappingProvider == null) {
final Path mappingsPath = getMappingsPath();
if (!Files.exists(mappingsPath)) {
exists = false;
return null;
}
try {
mappingProvider = TinyRemapperHelper.create(
mappingsPath,
getOptions().getFrom().get(),
getOptions().getTo().get(),
false
);
} catch (IOException e) {
throw new UncheckedIOException("Failed to read mappings from: " + mappingsPath, e);
}
}
return mappingProvider;
}
// We should always find the file in the task outputs, regardless of if it exists or not.
private Path getMappingsPath() {
for (File file : getOptions().getCompileOutputs().getFiles()) {
if (file.getName().equals(getOptions().getMixinMappingFileName().get())) {
return file.toPath();
}
}
throw new RuntimeException("Failed to find mixin mappings file: " + getOptions().getMixinMappingFileName().get());
}
}

View File

@@ -0,0 +1,141 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2024 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.task.service;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import com.google.gson.JsonObject;
import dev.architectury.loom.extensions.ModBuildExtensions;
import org.gradle.api.Project;
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.SourceSet;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.extension.MixinExtension;
import net.fabricmc.loom.task.AbstractRemapJarTask;
import net.fabricmc.loom.task.RemapJarTask;
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.Service;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.loom.util.service.ServiceType;
public class MixinRefmapService extends Service<MixinRefmapService.Options> {
public static final ServiceType<Options, MixinRefmapService> TYPE = new ServiceType<>(Options.class, MixinRefmapService.class);
public interface Options extends Service.Options {
@Input
ListProperty<String> getMixinConfigs();
@Input
Property<String> getRefmapName();
}
public static Provider<List<Options>> createOptions(RemapJarTask task) {
final Project project = task.getProject();
return project.provider(() -> {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
if (!extension.getMixin().getUseLegacyMixinAp().get()) {
return List.of();
}
final MixinExtension mixinExtension = extension.getMixin();
List<Provider<Options>> options = new ArrayList<>();
for (SourceSet sourceSet : mixinExtension.getMixinSourceSets()) {
MixinExtension.MixinInformationContainer container = Objects.requireNonNull(
MixinExtension.getMixinInformationContainer(sourceSet)
);
final List<String> rootPaths = AbstractRemapJarTask.getRootPaths(sourceSet.getResources().getSrcDirs());
final String refmapName = container.refmapNameProvider().get();
final List<String> mixinConfigs = container.sourceSet().getResources()
.matching(container.mixinConfigPattern())
.getFiles()
.stream()
.map(AbstractRemapJarTask.relativePath(rootPaths))
.toList();
options.add(createOptions(project, mixinConfigs, refmapName));
}
return options.stream().map(Provider::get).toList();
});
}
private static Provider<Options> createOptions(Project project, List<String> mixinConfigs, String refmapName) {
return TYPE.create(project, o -> {
o.getMixinConfigs().set(mixinConfigs);
o.getRefmapName().set(refmapName);
});
}
public MixinRefmapService(Options options, ServiceFactory serviceFactory) {
super(options, serviceFactory);
}
public void applyToJar(Path path, boolean readConfigsFromManifest) throws IOException {
final FabricModJson fabricModJson = FabricModJsonFactory.createFromZipNullable(path);
final List<String> allMixinConfigs = new ArrayList<>();
if (fabricModJson != null) {
allMixinConfigs.addAll(fabricModJson.getMixinConfigurations());
}
if (readConfigsFromManifest) {
allMixinConfigs.addAll(ModBuildExtensions.readMixinConfigsFromManifest(path.toFile()));
}
if (allMixinConfigs.isEmpty()) {
return;
}
final List<String> mixinConfigs = getOptions().getMixinConfigs().get().stream()
.filter(allMixinConfigs::contains)
.toList();
final String refmapName = getOptions().getRefmapName().get();
if (ZipUtils.contains(path, refmapName)) {
int transformed = ZipUtils.transformJson(JsonObject.class, path, mixinConfigs.stream().collect(Collectors.toMap(s -> s, s -> json -> {
if (!json.has("refmap")) {
json.addProperty("refmap", refmapName);
}
return json;
})));
}
}
}

View File

@@ -1,140 +0,0 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 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.Closeable;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import org.gradle.api.Project;
import org.gradle.api.file.RegularFileProperty;
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 net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
import net.fabricmc.loom.util.TinyRemapperHelper;
import net.fabricmc.loom.util.newService.Service;
import net.fabricmc.loom.util.newService.ServiceFactory;
import net.fabricmc.loom.util.newService.ServiceType;
import net.fabricmc.mappingio.MappingReader;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
import net.fabricmc.tinyremapper.IMappingProvider;
/**
* A service that provides mappings for remapping.
*/
public final class NewMappingsService extends Service<NewMappingsService.Options> implements Closeable {
public static ServiceType<Options, NewMappingsService> TYPE = new ServiceType<>(Options.class, NewMappingsService.class);
public interface Options extends Service.Options {
@InputFile
RegularFileProperty getMappingsFile();
@Input
Property<String> getFrom();
@Input
Property<String> getTo();
@Input
Property<Boolean> getRemapLocals();
}
/**
* Returns options for creating a new mappings service, with a given mappings file.
*/
public static Provider<Options> createOptions(Project project, Path mappingsFile, String from, String to, boolean remapLocals) {
return TYPE.create(project, o -> {
o.getMappingsFile().set(project.file(mappingsFile));
o.getFrom().set(from);
o.getTo().set(to);
o.getRemapLocals().set(remapLocals);
});
}
/**
* Returns options for creating a new mappings service, using the mappings as specified in the project's mapping configuration.
*/
public static Provider<Options> createOptionsWithProjectMappings(Project project, String from, String to) {
final MappingConfiguration mappingConfiguration = LoomGradleExtension.get(project).getMappingConfiguration();
return createOptions(project, mappingConfiguration.tinyMappings, from, to, false);
}
public NewMappingsService(Options options, ServiceFactory serviceFactory) {
super(options, serviceFactory);
}
private IMappingProvider mappingProvider = null;
private MemoryMappingTree memoryMappingTree = null;
public IMappingProvider getMappingsProvider() {
if (mappingProvider == null) {
try {
mappingProvider = TinyRemapperHelper.create(
getMappingsPath(),
getFrom(),
getTo(),
getOptions().getRemapLocals().get()
);
} catch (IOException e) {
throw new UncheckedIOException("Failed to read mappings from: " + getMappingsPath(), e);
}
}
return mappingProvider;
}
public MemoryMappingTree getMemoryMappingTree() {
if (memoryMappingTree == null) {
memoryMappingTree = new MemoryMappingTree();
try {
MappingReader.read(getMappingsPath(), memoryMappingTree);
} catch (IOException e) {
throw new UncheckedIOException("Failed to read mappings from: " + getMappingsPath(), e);
}
}
return memoryMappingTree;
}
public String getFrom() {
return getOptions().getFrom().get();
}
public String getTo() {
return getOptions().getTo().get();
}
public Path getMappingsPath() {
return getOptions().getMappingsFile().get().getAsFile().toPath();
}
@Override
public void close() {
mappingProvider = null;
}
}

View File

@@ -45,9 +45,9 @@ import net.fabricmc.loom.util.DeletingFileVisitor;
import net.fabricmc.loom.util.FileSystemUtil;
import net.fabricmc.loom.util.SourceRemapper;
import net.fabricmc.loom.util.ZipUtils;
import net.fabricmc.loom.util.newService.Service;
import net.fabricmc.loom.util.newService.ServiceFactory;
import net.fabricmc.loom.util.newService.ServiceType;
import net.fabricmc.loom.util.service.Service;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.loom.util.service.ServiceType;
import net.fabricmc.lorenztiny.TinyMappingsReader;
public final class SourceRemapperService extends Service<SourceRemapperService.Options> {
@@ -55,7 +55,7 @@ public final class SourceRemapperService extends Service<SourceRemapperService.O
public interface Options extends Service.Options {
@Nested
Property<NewMappingsService.Options> getMappings();
Property<MappingsService.Options> getMappings();
@Input
Property<Integer> getJavaCompileRelease();
@InputFiles
@@ -64,10 +64,10 @@ public final class SourceRemapperService extends Service<SourceRemapperService.O
public static Provider<Options> createOptions(RemapSourcesJarTask task) {
return TYPE.create(task.getProject(), o -> {
o.getMappings().set(NewMappingsService.createOptionsWithProjectMappings(
o.getMappings().set(MappingsService.createOptionsWithProjectMappings(
task.getProject(),
task.getSourceNamespace().get(),
task.getTargetNamespace().get()
task.getSourceNamespace(),
task.getTargetNamespace()
));
o.getJavaCompileRelease().set(SourceRemapper.getJavaCompileRelease(task.getProject()));
o.getClasspath().from(task.getClasspath());
@@ -123,7 +123,7 @@ public final class SourceRemapperService extends Service<SourceRemapperService.O
mercury.setGracefulClasspathChecks(true);
mercury.setSourceCompatibilityFromRelease(getOptions().getJavaCompileRelease().get());
NewMappingsService mappingsService = getServiceFactory().get(getOptions().getMappings());
MappingsService mappingsService = getServiceFactory().get(getOptions().getMappings());
var tinyMappingsReader = new TinyMappingsReader(mappingsService.getMemoryMappingTree(), mappingsService.getFrom(), mappingsService.getTo()).read();
mercury.getProcessors().add(MercuryRemapper.create(tinyMappingsReader));

View File

@@ -24,6 +24,7 @@
package net.fabricmc.loom.task.service;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
@@ -35,111 +36,83 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.StringJoiner;
import org.gradle.api.Project;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.invocation.Gradle;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.file.FileCollection;
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.Nested;
import org.gradle.api.tasks.Optional;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.build.IntermediaryNamespaces;
import net.fabricmc.loom.build.mixin.AnnotationProcessorInvoker;
import net.fabricmc.loom.extension.RemapperExtensionHolder;
import net.fabricmc.loom.task.AbstractRemapJarTask;
import net.fabricmc.loom.util.Constants;
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;
import net.fabricmc.loom.util.service.SharedService;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.service.Service;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.loom.util.service.ServiceType;
import net.fabricmc.tinyremapper.IMappingProvider;
import net.fabricmc.tinyremapper.InputTag;
import net.fabricmc.tinyremapper.TinyRemapper;
import net.fabricmc.tinyremapper.extension.mixin.MixinExtension;
public class TinyRemapperService implements SharedService {
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 boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get();
final @Nullable KotlinClasspathService kotlinClasspathService = KotlinClasspathService.getOrCreateIfRequired(serviceManager, project);
public class TinyRemapperService extends Service<TinyRemapperService.Options> implements Closeable {
public static final ServiceType<Options, TinyRemapperService> TYPE = new ServiceType<>(Options.class, TinyRemapperService.class);
// 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(":");
joiner.add(extension.getMappingConfiguration().getBuildServiceName("remapJarService", from, to));
joiner.add(remapJarTask.getName());
if (kotlinClasspathService != null) {
joiner.add("kotlin-" + kotlinClasspathService.version());
}
// TODO remove this when removing shared service manager.
joiner.add(project.getPath());
extension.getKnownIndyBsms().get().stream().sorted().forEach(joiner::add);
if (extension.isForgeLike()) {
joiner.add(extension.getPlatform().get().id());
}
final String id = joiner.toString();
TinyRemapperService service = serviceManager.getOrCreateService(id, () -> {
List<IMappingProvider> mappings = new ArrayList<>();
mappings.add(MappingsService.createDefault(project, serviceManager, from, to).getMappingsProvider());
if (legacyMixin) {
mappings.add(gradleMixinMappingProvider(serviceManager, project.getGradle(), extension.getMappingConfiguration().mappingsIdentifier, from, to));
}
return new TinyRemapperService(mappings, !legacyMixin, kotlinClasspathService, extension.getKnownIndyBsms().get(), extension.getRemapperExtensions().get(), from, to, project.getObjects());
});
final ConfigurationContainer configurations = project.getConfigurations();
ConfigurableFileCollection excludedMinecraftJars = project.files();
List<Path> classPath = remapJarTask.getClasspath()
.minus(configurations.getByName(Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES))
.minus(configurations.getByName(Constants.Configurations.MINECRAFT_RUNTIME_LIBRARIES))
.minus(excludedMinecraftJars)
.getFiles()
.stream()
.map(File::toPath)
.filter(Files::exists)
.toList();
service.readClasspath(classPath);
return service;
public interface Options extends Service.Options {
@Input
Property<String> getFrom();
@Input
Property<String> getTo();
@Nested
ListProperty<MappingsService.Options> getMappings();
@Input
Property<Boolean> getUselegacyMixinAP();
@Nested
ListProperty<MixinAPMappingService.Options> getMixinApMappings();
@Nested
@Optional
Property<KotlinClasspathService.Options> getKotlinClasspathService();
@InputFiles
ConfigurableFileCollection getClasspath();
@Input
ListProperty<String> getKnownIndyBsms();
@Input
ListProperty<RemapperExtensionHolder> getRemapperExtensions();
}
// Add all of the mixin mappings from all loom projects.
private static IMappingProvider gradleMixinMappingProvider(SharedServiceManager serviceManager, Gradle gradle, String mappingId, String from, String to) {
return out -> GradleUtils.allLoomProjects(gradle, project -> {
public static Provider<Options> createOptions(AbstractRemapJarTask remapJarTask) {
final Project project = remapJarTask.getProject();
return TYPE.create(project, options -> {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final ConfigurationContainer configurations = project.getConfigurations();
final boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get();
final FileCollection classpath = remapJarTask.getClasspath()
.minus(configurations.getByName(Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES))
.minus(configurations.getByName(Constants.Configurations.MINECRAFT_RUNTIME_LIBRARIES));
if (!mappingId.equals(extension.getMappingConfiguration().mappingsIdentifier)) {
// Only find mixin mappings that are from other projects with the same mapping id.
return;
options.getFrom().set(remapJarTask.getSourceNamespace());
options.getTo().set(remapJarTask.getTargetNamespace());
options.getMappings().add(MappingsService.createOptionsWithProjectMappings(project, options.getFrom(), options.getTo()));
if (legacyMixin) {
options.getMixinApMappings().set(MixinAPMappingService.createOptions(project, options.getFrom(), options.getTo().map(to -> IntermediaryNamespaces.replaceMixinIntermediaryNamespace(project, to))));
}
for (SourceSet sourceSet : SourceSetHelper.getSourceSets(project)) {
final File mixinMappings = AnnotationProcessorInvoker.getMixinMappingsForSourceSet(project, sourceSet);
if (!mixinMappings.exists()) {
continue;
}
final String newTo = IntermediaryNamespaces.replaceMixinIntermediaryNamespace(project, to);
MappingsService service = MappingsService.create(serviceManager, mixinMappings.getAbsolutePath(), mixinMappings.toPath(), from, newTo, false);
service.getMappingsProvider().load(out);
}
options.getUselegacyMixinAP().set(legacyMixin);
options.getKotlinClasspathService().set(KotlinClasspathService.createOptions(project));
options.getClasspath().from(classpath);
options.getKnownIndyBsms().set(extension.getKnownIndyBsms());
options.getRemapperExtensions().set(extension.getRemapperExtensions());
});
}
@@ -151,30 +124,50 @@ public class TinyRemapperService implements SharedService {
// Set to true once remapping has started, once set no inputs can be read.
private boolean isRemapping = false;
private TinyRemapperService(List<IMappingProvider> mappings, boolean useMixinExtension, @Nullable KotlinClasspath kotlinClasspath, Set<String> knownIndyBsms, List<RemapperExtensionHolder> remapperExtensions, String sourceNamespace, String targetNamespace, ObjectFactory objectFactory) {
TinyRemapper.Builder builder = TinyRemapper.newRemapper().withKnownIndyBsm(knownIndyBsms);
public TinyRemapperService(Options options, ServiceFactory serviceFactory) {
super(options, serviceFactory);
tinyRemapper = createTinyRemapper();
readClasspath();
}
for (IMappingProvider provider : mappings) {
builder.withMappings(provider);
private TinyRemapper createTinyRemapper() {
TinyRemapper.Builder builder = TinyRemapper.newRemapper()
.withKnownIndyBsm(Set.copyOf(getOptions().getKnownIndyBsms().get()));
for (MappingsService.Options options : getOptions().getMappings().get()) {
MappingsService mappingsService = getServiceFactory().get(options);
builder.withMappings(mappingsService.getMappingsProvider());
}
if (useMixinExtension) {
builder.extension(new net.fabricmc.tinyremapper.extension.mixin.MixinExtension());
if (!getOptions().getUselegacyMixinAP().get()) {
builder.extension(new MixinExtension());
}
if (kotlinClasspath != null) {
kotlinRemapperClassloader = KotlinRemapperClassloader.create(kotlinClasspath);
if (getOptions().getKotlinClasspathService().isPresent()) {
KotlinClasspathService kotlinClasspathService = getServiceFactory().get(getOptions().getKotlinClasspathService());
kotlinRemapperClassloader = KotlinRemapperClassloader.create(kotlinClasspathService);
builder.extension(kotlinRemapperClassloader.getTinyRemapperExtension());
}
for (RemapperExtensionHolder holder : remapperExtensions) {
holder.apply(builder, sourceNamespace, targetNamespace, objectFactory);
for (RemapperExtensionHolder holder : getOptions().getRemapperExtensions().get()) {
holder.apply(builder, getOptions().getFrom().get(), getOptions().getTo().get());
}
tinyRemapper = builder.build();
if (getOptions().getUselegacyMixinAP().get()) {
for (MixinAPMappingService.Options options : getOptions().getMixinApMappings().get()) {
MixinAPMappingService mixinAPMappingService = getServiceFactory().get(options);
IMappingProvider provider = mixinAPMappingService.getMappingsProvider();
if (provider != null) {
builder.withMappings(provider);
}
}
}
return builder.build();
}
public synchronized InputTag getOrCreateTag(Path file) {
public InputTag getOrCreateTag(Path file) {
InputTag tag = inputTagMap.get(file.toAbsolutePath().toString());
if (tag == null) {
@@ -186,34 +179,30 @@ public class TinyRemapperService implements SharedService {
}
public TinyRemapper getTinyRemapperForRemapping() {
synchronized (this) {
isRemapping = true;
return Objects.requireNonNull(tinyRemapper, "Tiny remapper has not been setup");
}
isRemapping = true;
return Objects.requireNonNull(tinyRemapper, "Tiny remapper has not been setup");
}
public synchronized TinyRemapper getTinyRemapperForInputs() {
synchronized (this) {
if (isRemapping) {
throw new IllegalStateException("Cannot read inputs as remapping has already started");
}
return tinyRemapper;
public TinyRemapper getTinyRemapperForInputs() {
if (isRemapping) {
throw new IllegalStateException("Cannot read inputs as remapping has already started");
}
return tinyRemapper;
}
void readClasspath(List<Path> paths) {
private void readClasspath() {
List<Path> toRead = new ArrayList<>();
synchronized (classpath) {
for (Path path: paths) {
if (classpath.contains(path)) {
continue;
}
for (File file : getOptions().getClasspath().getFiles()) {
Path path = file.toPath();
toRead.add(path);
classpath.add(path);
if (classpath.contains(path) || Files.notExists(path)) {
continue;
}
toRead.add(path);
classpath.add(path);
}
if (toRead.isEmpty()) {

View File

@@ -53,24 +53,24 @@ import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.build.IntermediaryNamespaces;
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
import net.fabricmc.loom.task.service.LorenzMappingService;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.service.ServiceFactory;
public class SourceRemapper {
private final Project project;
private final SharedServiceManager serviceManager;
private final ServiceFactory serviceFactory;
private String from;
private String to;
private final List<Consumer<ProgressLogger>> remapTasks = new ArrayList<>();
private Mercury mercury;
public SourceRemapper(Project project, SharedServiceManager serviceManager, boolean toNamed) {
this(project, serviceManager, toNamed ? IntermediaryNamespaces.runtimeIntermediary(project) : "named", !toNamed ? IntermediaryNamespaces.runtimeIntermediary(project) : "named");
public SourceRemapper(Project project, ServiceFactory serviceFactory, boolean toNamed) {
this(project, serviceFactory, toNamed ? IntermediaryNamespaces.runtimeIntermediary(project) : "named", !toNamed ? IntermediaryNamespaces.runtimeIntermediary(project) : "named");
}
public SourceRemapper(Project project, SharedServiceManager serviceManager, String from, String to) {
public SourceRemapper(Project project, ServiceFactory serviceFactory, String from, String to) {
this.project = project;
this.serviceManager = serviceManager;
this.serviceFactory = serviceFactory;
this.from = from;
this.to = to;
}
@@ -174,11 +174,12 @@ public class SourceRemapper {
LoomGradleExtension extension = LoomGradleExtension.get(project);
MappingConfiguration mappingConfiguration = extension.getMappingConfiguration();
MappingSet mappings = LorenzMappingService.create(serviceManager,
mappingConfiguration,
LorenzMappingService lorenzMappingService = serviceFactory.get(LorenzMappingService.createOptions(
project,
mappingConfiguration,
Objects.requireNonNull(MappingsNamespace.of(from)),
Objects.requireNonNull(MappingsNamespace.of(to))
).mappings();
Objects.requireNonNull(MappingsNamespace.of(to))));
MappingSet mappings = lorenzMappingService.getMappings();
Mercury mercury = createMercuryWithClassPath(project, MappingsNamespace.of(to) == MappingsNamespace.NAMED);
mercury.setSourceCompatibilityFromRelease(getJavaCompileRelease(project));

View File

@@ -33,11 +33,12 @@ import java.util.regex.Pattern;
import com.google.common.collect.ImmutableMap;
import dev.architectury.loom.util.MappingOption;
import org.gradle.api.Project;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.loom.util.srg.InnerClassRemapper;
import net.fabricmc.mappingio.MappingReader;
import net.fabricmc.mappingio.tree.MappingTree;
@@ -64,14 +65,14 @@ public final class TinyRemapperHelper {
private TinyRemapperHelper() {
}
public static TinyRemapper getTinyRemapper(Project project, SharedServiceManager serviceManager, String fromM, String toM) throws IOException {
return getTinyRemapper(project, serviceManager, fromM, toM, false, (builder) -> { }, Set.of());
public static TinyRemapper getTinyRemapper(Project project, ServiceFactory serviceFactory, String fromM, String toM) throws IOException {
return getTinyRemapper(project, serviceFactory, fromM, toM, false, (builder) -> { }, Set.of());
}
public static TinyRemapper getTinyRemapper(Project project, SharedServiceManager serviceManager, String fromM, String toM, boolean fixRecords, Consumer<TinyRemapper.Builder> builderConsumer, Set<String> fromClassNames) throws IOException {
public static TinyRemapper getTinyRemapper(Project project, ServiceFactory serviceFactory, String fromM, String toM, boolean fixRecords, Consumer<TinyRemapper.Builder> builderConsumer, Set<String> fromClassNames) throws IOException {
LoomGradleExtension extension = LoomGradleExtension.get(project);
final MappingOption mappingOption = MappingOption.forPlatform(extension);
MemoryMappingTree mappingTree = extension.getMappingConfiguration().getMappingsService(serviceManager, mappingOption).getMappingTree();
MemoryMappingTree mappingTree = extension.getMappingConfiguration().getMappingsService(project, serviceFactory, mappingOption).getMappingTree();
if (fixRecords && !mappingTree.getSrcNamespace().equals(fromM)) {
throw new IllegalStateException("Mappings src namespace must match remap src namespace, expected " + fromM + " but got " + mappingTree.getSrcNamespace());

View File

@@ -75,6 +75,11 @@ public class GradleTypeAdapter implements TypeAdapterFactory {
@Override
public void write(JsonWriter out, T property) throws IOException {
if (!property.isPresent()) {
out.nullValue();
return;
}
final Object o = property.get();
final TypeAdapter adapter = gson.getAdapter(o.getClass());
adapter.write(out, o);
@@ -102,6 +107,11 @@ public class GradleTypeAdapter implements TypeAdapterFactory {
private static final class RegularFilePropertyTypeAdapter<T extends RegularFileProperty> extends WriteOnlyTypeAdapter<T> {
@Override
public void write(JsonWriter out, T property) throws IOException {
if (!property.isPresent()) {
out.nullValue();
return;
}
final File file = property.get().getAsFile();
out.value(file.getAbsolutePath());
}

View File

@@ -24,6 +24,7 @@
package net.fabricmc.loom.util.kotlin;
import java.io.File;
import java.io.UncheckedIOException;
import java.net.MalformedURLException;
import java.net.URL;
@@ -32,27 +33,40 @@ import java.util.stream.Collectors;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.jetbrains.annotations.Nullable;
import org.gradle.api.file.ConfigurableFileCollection;
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 net.fabricmc.loom.util.service.SharedService;
import net.fabricmc.loom.util.service.SharedServiceManager;
import net.fabricmc.loom.util.service.Service;
import net.fabricmc.loom.util.service.ServiceFactory;
import net.fabricmc.loom.util.service.ServiceType;
public record KotlinClasspathService(Set<URL> classpath, String version) implements KotlinClasspath, SharedService {
@Nullable
public static KotlinClasspathService getOrCreateIfRequired(SharedServiceManager sharedServiceManager, Project project) {
public final class KotlinClasspathService extends Service<KotlinClasspathService.Options> implements KotlinClasspath {
public static ServiceType<Options, KotlinClasspathService> TYPE = new ServiceType<>(Options.class, KotlinClasspathService.class);
public interface Options extends Service.Options {
@InputFiles
ConfigurableFileCollection getClasspath();
@Input
Property<String> getKotlinVersion();
}
public static Provider<Options> createOptions(Project project) {
if (!KotlinPluginUtils.hasKotlinPlugin(project)) {
return null;
// Return an empty provider
return project.getObjects().property(Options.class);
}
return getOrCreate(sharedServiceManager, project, KotlinPluginUtils.getKotlinPluginVersion(project), KotlinPluginUtils.getKotlinMetadataVersion());
return createOptions(
project,
KotlinPluginUtils.getKotlinPluginVersion(project),
KotlinPluginUtils.getKotlinMetadataVersion()
);
}
public static synchronized KotlinClasspathService getOrCreate(SharedServiceManager sharedServiceManager, Project project, String kotlinVersion, String kotlinMetadataVersion) {
final String id = "kotlinclasspath:%s:%s".formatted(kotlinVersion, kotlinMetadataVersion);
return sharedServiceManager.getOrCreateService(id, () -> create(project, kotlinVersion, kotlinMetadataVersion));
}
private static KotlinClasspathService create(Project project, String kotlinVersion, String kotlinMetadataVersion) {
private static Provider<Options> createOptions(Project project, String kotlinVersion, String kotlinMetadataVersion) {
// Create a detached config to resolve the kotlin std lib for the provided version.
Configuration detachedConfiguration = project.getConfigurations().detachedConfiguration(
project.getDependencies().create("org.jetbrains.kotlin:kotlin-stdlib:" + kotlinVersion),
@@ -60,15 +74,36 @@ public record KotlinClasspathService(Set<URL> classpath, String version) impleme
project.getDependencies().create("org.jetbrains.kotlinx:kotlinx-metadata-jvm:" + kotlinMetadataVersion)
);
Set<URL> classpath = detachedConfiguration.getFiles().stream()
.map(file -> {
try {
return file.toURI().toURL();
} catch (MalformedURLException e) {
throw new UncheckedIOException(e);
}
}).collect(Collectors.toSet());;
return TYPE.create(project, options -> {
options.getClasspath().from(detachedConfiguration);
options.getKotlinVersion().set(kotlinVersion);
});
}
return new KotlinClasspathService(classpath, kotlinVersion);
public KotlinClasspathService(Options options, ServiceFactory serviceFactory) {
super(options, serviceFactory);
}
@Override
public String version() {
return getOptions().getKotlinVersion().get();
}
@Override
public Set<URL> classpath() {
return getOptions()
.getClasspath()
.getFiles()
.stream()
.map(KotlinClasspathService::fileToUrl)
.collect(Collectors.toSet());
}
private static URL fileToUrl(File file) {
try {
return file.toURI().toURL();
} catch (MalformedURLException e) {
throw new UncheckedIOException(e);
}
}
}

View File

@@ -1,94 +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.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 BuildSharedServiceManager() {
LOGGER.debug("New BuildSharedServiceManager instance");
}
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

@@ -22,7 +22,7 @@
* SOFTWARE.
*/
package net.fabricmc.loom.util.newService;
package net.fabricmc.loom.util.service;
import java.io.Closeable;
import java.io.IOException;

View File

@@ -22,7 +22,7 @@
* SOFTWARE.
*/
package net.fabricmc.loom.util.newService;
package net.fabricmc.loom.util.service;
import java.io.Closeable;
import java.io.IOException;
@@ -51,8 +51,6 @@ public final class ScopedServiceFactory implements ServiceFactory, Closeable {
return service;
}
// TODO skip serialization if we know there is no service with the same type
// If the service is not already created, serialize the options and check the json map as it may be an equivalent service
String key = getOptionsCacheKey(options);
//noinspection unchecked

View File

@@ -1,35 +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.util.service;
public final class ScopedSharedServiceManager extends SharedServiceManager implements AutoCloseable {
public ScopedSharedServiceManager() {
}
@Override
public void close() {
onFinish();
}
}

View File

@@ -22,7 +22,7 @@
* SOFTWARE.
*/
package net.fabricmc.loom.util.newService;
package net.fabricmc.loom.util.service;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;

View File

@@ -22,9 +22,10 @@
* SOFTWARE.
*/
package net.fabricmc.loom.util.newService;
package net.fabricmc.loom.util.service;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.jetbrains.annotations.Nullable;
/**
* A factory for creating {@link Service} instances.
@@ -38,10 +39,26 @@ public interface ServiceFactory {
* @param <S> The service type.
* @return The service instance.
*/
default <O extends Service.Options, S extends Service<O>> S get(Property<O> options) {
default <O extends Service.Options, S extends Service<O>> S get(Provider<O> options) {
return get(options.get());
}
/**
* Gets or creates a service instance with the given options, or returns null if the options are not present.
* @param options The options to use.
* @param <O> The options type.
* @param <S> The service type.
* @return The service instance, or null if the options are not present.
*/
@Nullable
default <O extends Service.Options, S extends Service<O>> S getOrNull(Provider<O> options) {
if (options.isPresent()) {
return get(options);
} else {
return null;
}
}
/**
* Gets or creates a service instance with the given options.
*

View File

@@ -22,7 +22,7 @@
* SOFTWARE.
*/
package net.fabricmc.loom.util.newService;
package net.fabricmc.loom.util.service;
import org.gradle.api.Action;
import org.gradle.api.Project;

View File

@@ -1,34 +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.util.service;
import java.io.Closeable;
import java.io.IOException;
public interface SharedService extends Closeable {
@Override
default void close() throws IOException {
}
}

View File

@@ -1,99 +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.util.service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
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 abstract class SharedServiceManager {
private static final Logger LOGGER = LoggerFactory.getLogger(BuildSharedServiceManager.class);
private final Map<String, SharedService> sharedServiceMap = new HashMap<>();
private boolean shutdown = false;
SharedServiceManager() {
LOGGER.info("Creating new SharedServiceManager({})", hashCode());
}
public <S extends SharedService> S getOrCreateService(String id, Supplier<S> function) {
synchronized (sharedServiceMap) {
if (shutdown) {
throw new UnsupportedOperationException("Cannot get or create service has the manager has been shutdown.");
}
//noinspection unchecked
S sharedService = (S) sharedServiceMap.get(id);
if (sharedService == null) {
LOGGER.debug("Creating service for {}", id);
sharedService = function.get();
sharedServiceMap.put(id, sharedService);
}
return sharedService;
}
}
protected void onFinish() {
synchronized (sharedServiceMap) {
shutdown = true;
}
LOGGER.info("Closing SharedServiceManager({})", hashCode());
final List<IOException> exceptionList = new ArrayList<>();
for (SharedService sharedService : sharedServiceMap.values()) {
try {
sharedService.close();
} catch (IOException e) {
exceptionList.add(e);
}
}
sharedServiceMap.clear();
// This is required to ensure that mercury releases all of the file handles.
System.gc();
if (!exceptionList.isEmpty()) {
// Done to try and close all the services.
RuntimeException exception = new RuntimeException("Failed to close all shared services");
exceptionList.forEach(exception::addSuppressed);
throw exception;
}
}
}

View File

@@ -1,57 +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.util.service;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.gradle.api.provider.Property;
// Massive hack to work around WorkerExecutor.noIsolation() doing isolation checks.
public final class UnsafeWorkQueueHelper {
private static final Map<String, SharedService> SERVICE_MAP = new ConcurrentHashMap<>();
private UnsafeWorkQueueHelper() {
}
public static String create(SharedService service) {
final String uuid = UUID.randomUUID().toString();
SERVICE_MAP.put(uuid, service);
return uuid;
}
public static <S> S get(Property<String> property, Class<S> clazz) {
SharedService service = SERVICE_MAP.remove(property.get());
if (service == null) {
throw new NullPointerException("Failed to get service for " + clazz);
}
//noinspection unchecked
return (S) service;
}
}

View File

@@ -44,7 +44,7 @@ class FabricAPIBenchmark implements GradleProjectTestTrait {
allowExistingRepo: true,
repo: "https://github.com/FabricMC/fabric.git",
commit: "efa5891941a32589207dc58c2e77183d599465b8",
commit: "41bc64cd617f03d49ecc4a4f7788cb65d465415c",
patch: "fabric_api"
)

View File

@@ -61,6 +61,7 @@ class ConfigurationCacheTest extends Specification implements GradleProjectTestT
"jar" | _
"check" | _
"remapSourcesJar" | _
"build" | _
}
// Test GradleUtils.configurationInputFile invalidates the cache when the file changes

View File

@@ -34,7 +34,7 @@ import net.fabricmc.loom.api.remapping.RemapperExtension
import net.fabricmc.loom.api.remapping.RemapperParameters
import net.fabricmc.loom.util.Constants
abstract class TestRemapperExtension implements RemapperExtension<Params> {
class TestRemapperExtension implements RemapperExtension<Params> {
final Params parameters
@Inject

View File

@@ -44,10 +44,23 @@ class GradleTypeAdapterTest extends Specification {
def json = GradleTypeAdapter.GSON.toJson(property)
then:
1 * property.isPresent() >> true
1 * property.get() >> "value"
json == "\"value\""
}
def "Empty Property"() {
given:
def property = Mock(Property)
when:
def json = GradleTypeAdapter.GSON.toJson(property)
then:
1 * property.isPresent() >> false
json == "null"
}
@IgnoreIf({ os.windows })
def "FileCollection"() {
given:
@@ -74,11 +87,24 @@ class GradleTypeAdapterTest extends Specification {
def json = GradleTypeAdapter.GSON.toJson(regularFileProperty)
then:
1 * regularFileProperty.isPresent() >> true
1 * regularFileProperty.get() >> regularFile
1 * regularFile.getAsFile() >> file
json == "\"${file.getAbsolutePath()}\""
}
def "Empty RegularFileProperty"() {
given:
def regularFileProperty = Mock(RegularFileProperty)
when:
def json = GradleTypeAdapter.GSON.toJson(regularFileProperty)
then:
1 * regularFileProperty.isPresent() >> false
json == "null"
}
def "ListProperty"() {
given:
def listProperty = Mock(ListProperty)

View File

@@ -38,6 +38,7 @@ class LoomMocks {
def minecraftVersionProperty = GradleTestUtil.mockProperty(minecraftVersion)
def intermediaryUrlProperty = GradleTestUtil.mockProperty(intermediaryUrl)
def downloaderProperty = GradleTestUtil.mockProperty(Download.&create as Function)
def refreshDeps = GradleTestUtil.mockProperty(false)
Objects.requireNonNull(minecraftVersionProperty.get())
@@ -45,6 +46,7 @@ class LoomMocks {
when(mock.getMinecraftVersion()).thenReturn(minecraftVersionProperty)
when(mock.getIntermediaryUrl()).thenReturn(intermediaryUrlProperty)
when(mock.getDownloader()).thenReturn(downloaderProperty)
when(mock.getRefreshDeps()).thenReturn(refreshDeps)
return mock
}
}

View File

@@ -28,13 +28,15 @@ import spock.lang.Specification
import net.fabricmc.loom.configuration.providers.BundleMetadata
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarSplitter
import net.fabricmc.loom.test.LoomTestConstants
import net.fabricmc.loom.test.util.GradleTestUtil
import net.fabricmc.loom.util.download.Download
class MinecraftJarSplitterTest extends Specification {
public static final String CLIENT_JAR_URL = "https://launcher.mojang.com/v1/objects/7e46fb47609401970e2818989fa584fd467cd036/client.jar"
public static final String SERVER_BUNDLE_JAR_URL = "https://launcher.mojang.com/v1/objects/125e5adf40c659fd3bce3e66e67a16bb49ecc1b9/server.jar"
public static final File mcJarDir = File.createTempDir()
public static final File mcJarDir = new File(LoomTestConstants.TEST_DIR, "jar-splitter")
def "split jars"() {
given:
@@ -63,7 +65,9 @@ class MinecraftJarSplitterTest extends Specification {
if (!dst.exists()) {
dst.parentFile.mkdirs()
dst << new URL(url).newInputStream()
Download.create(url)
.defaultCache()
.downloadPath(dst.toPath())
}
return dst

View File

@@ -42,6 +42,7 @@ class FileMappingLayerTest extends LayeredMappingsSpecification {
setup:
intermediaryUrl = INTERMEDIARY_1_17_URL
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_17
mockMinecraftProvider.minecraftVersion() >> "1.17"
setupType.setup.delegate = this
def mappingFile = setupType.setup.call()
when:
@@ -71,6 +72,7 @@ class FileMappingLayerTest extends LayeredMappingsSpecification {
setup:
intermediaryUrl = INTERMEDIARY_1_17_URL
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_17
mockMinecraftProvider.minecraftVersion() >> "1.17"
def mappingsDownload = VERSION_META_1_17.download('client_mappings')
def mappingsFile = new File(tempDir, 'mappings.txt')
Download.create(mappingsDownload.url())

View File

@@ -31,6 +31,7 @@ class IntermediaryMappingLayerTest extends LayeredMappingsSpecification {
setup:
intermediaryUrl = INTERMEDIARY_1_17_URL
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_17
mockMinecraftProvider.minecraftVersion() >> "1.17"
when:
def mappings = getSingleMapping(new IntermediaryMappingsSpec())
def tiny = getTiny(mappings)

View File

@@ -24,6 +24,7 @@
package net.fabricmc.loom.test.unit.layeredmappings
import java.nio.file.Files
import java.nio.file.Path
import java.util.function.Supplier
import java.util.zip.ZipFile
@@ -45,6 +46,7 @@ import net.fabricmc.loom.configuration.providers.mappings.extras.unpick.UnpickLa
import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingLayer
import net.fabricmc.loom.configuration.providers.mappings.utils.AddConstructorMappingVisitor
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider
import net.fabricmc.loom.test.LoomTestConstants
import net.fabricmc.loom.test.unit.LoomMocks
import net.fabricmc.loom.util.download.Download
import net.fabricmc.loom.util.download.DownloadBuilder
@@ -60,7 +62,7 @@ abstract class LayeredMappingsSpecification extends Specification implements Lay
String intermediaryUrl
MappingContext mappingContext = new TestMappingContext()
File tempDir = File.createTempDir()
File tempDir = new File(LoomTestConstants.TEST_DIR, "layered/${getClass().name}")
Map<String, File> mavenFiles = [:]
@@ -70,8 +72,11 @@ abstract class LayeredMappingsSpecification extends Specification implements Lay
File downloadFile(String url, String name) {
File dst = new File(tempDir, name)
dst.parentFile.mkdirs()
dst << new URL(url).newInputStream()
if (!dst.exists()) {
Download.create(url)
.defaultCache()
.downloadPath(dst.toPath())
}
return dst
}
@@ -148,7 +153,15 @@ abstract class LayeredMappingsSpecification extends Specification implements Lay
@Override
Supplier<MemoryMappingTree> intermediaryTree() {
return {
IntermediateMappingsService.create(LoomMocks.intermediaryMappingsProviderMock("test", intermediaryUrl), minecraftProvider(), null).memoryMappingTree
def path = LoomTestConstants.TEST_DIR.toPath().resolve("intermediary").resolve(Objects.requireNonNull(minecraftVersion()) + ".tiny")
if (!Files.exists(path)) {
Files.createDirectories(path.parent)
def provider = LoomMocks.intermediaryMappingsProviderMock(minecraftVersion(), intermediaryUrl)
provider.provide(path, null)
}
return IntermediateMappingsService.createMemoryMappingTree(path, MappingsNamespace.OFFICIAL.toString())
}
}

View File

@@ -32,6 +32,7 @@ class MojangMappingLayerTest extends LayeredMappingsSpecification {
setup:
intermediaryUrl = INTERMEDIARY_1_17_URL
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_17
mockMinecraftProvider.minecraftVersion() >> "1.17"
when:
def mappings = getLayeredMappings(
new IntermediaryMappingsSpec(),
@@ -52,6 +53,7 @@ class MojangMappingLayerTest extends LayeredMappingsSpecification {
setup:
intermediaryUrl = INTERMEDIARY_1_17_URL
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_17
mockMinecraftProvider.minecraftVersion() >> "1.17"
when:
def mappings = getLayeredMappings(
new IntermediaryMappingsSpec(),

View File

@@ -34,6 +34,7 @@ class ParchmentMappingLayerTest extends LayeredMappingsSpecification {
setup:
intermediaryUrl = INTERMEDIARY_1_16_5_URL
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_16_5
mockMinecraftProvider.minecraftVersion() >> "1.16.5"
when:
withMavenFile(PARCHMENT_NOTATION, downloadFile(PARCHMENT_URL, "parchment.zip"))
def mappings = getLayeredMappings(
@@ -58,6 +59,7 @@ class ParchmentMappingLayerTest extends LayeredMappingsSpecification {
setup:
intermediaryUrl = INTERMEDIARY_1_16_5_URL
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_16_5
mockMinecraftProvider.minecraftVersion() >> "1.16.5"
when:
withMavenFile(PARCHMENT_NOTATION, downloadFile(PARCHMENT_URL, "parchment.zip"))
def mappings = getLayeredMappings(

View File

@@ -27,13 +27,13 @@ package net.fabricmc.loom.test.unit.service
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import net.fabricmc.loom.task.service.NewMappingsService
import net.fabricmc.loom.task.service.MappingsService
import net.fabricmc.loom.test.util.GradleTestUtil
class MappingsServiceTest extends ServiceTestBase {
def "get mapping tree"() {
given:
NewMappingsService service = factory.get(new TestOptions(
MappingsService service = factory.get(new TestOptions(
mappingsFile: GradleTestUtil.mockRegularFileProperty(new File("src/test/resources/mappings/PosInChunk.mappings")),
from: GradleTestUtil.mockProperty("intermediary"),
to: GradleTestUtil.mockProperty("named"),
@@ -49,11 +49,12 @@ class MappingsServiceTest extends ServiceTestBase {
service.to == "named"
}
static class TestOptions implements NewMappingsService.Options {
static class TestOptions implements MappingsService.Options {
RegularFileProperty mappingsFile
Property<String> from
Property<String> to
Property<Boolean> remapLocals = GradleTestUtil.mockProperty(false)
Property<String> serviceClass = serviceClassProperty(NewMappingsService.TYPE)
Property<Boolean> AllowNoneExistent = GradleTestUtil.mockProperty(false)
Property<String> serviceClass = serviceClassProperty(MappingsService.TYPE)
}
}

View File

@@ -31,9 +31,9 @@ import org.gradle.api.tasks.Input
import spock.lang.Specification
import net.fabricmc.loom.test.util.GradleTestUtil
import net.fabricmc.loom.util.newService.ScopedServiceFactory
import net.fabricmc.loom.util.newService.Service
import net.fabricmc.loom.util.newService.ServiceType
import net.fabricmc.loom.util.service.ScopedServiceFactory
import net.fabricmc.loom.util.service.Service
import net.fabricmc.loom.util.service.ServiceType
class ScopedServiceFactoryTest extends Specification {
def "create service"() {

View File

@@ -28,9 +28,9 @@ import org.gradle.api.provider.Property
import spock.lang.Specification
import net.fabricmc.loom.test.util.GradleTestUtil
import net.fabricmc.loom.util.newService.ScopedServiceFactory
import net.fabricmc.loom.util.newService.Service
import net.fabricmc.loom.util.newService.ServiceType
import net.fabricmc.loom.util.service.ScopedServiceFactory
import net.fabricmc.loom.util.service.Service
import net.fabricmc.loom.util.service.ServiceType
abstract class ServiceTestBase extends Specification {
ScopedServiceFactory factory

View File

@@ -31,7 +31,7 @@ import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.provider.Property
import org.intellij.lang.annotations.Language
import net.fabricmc.loom.task.service.NewMappingsService
import net.fabricmc.loom.task.service.MappingsService
import net.fabricmc.loom.task.service.SourceRemapperService
import net.fabricmc.loom.test.util.GradleTestUtil
import net.fabricmc.loom.util.DeletingFileVisitor
@@ -87,7 +87,7 @@ class SourceRemapperServiceTest extends ServiceTestBase {
""".trim()
static class TestOptions implements SourceRemapperService.Options {
Property<NewMappingsService.Options> mappings
Property<MappingsService.Options> mappings
Property<Integer> javaCompileRelease = GradleTestUtil.mockProperty(17)
ConfigurableFileCollection classpath = GradleTestUtil.mockConfigurableFileCollection()
Property<String> serviceClass = serviceClassProperty(SourceRemapperService.TYPE)

View File

@@ -52,6 +52,7 @@ class GradleTestUtil {
static <T> Property<T> mockProperty(T value) {
def mock = mock(Property.class)
when(mock.get()).thenReturn(Objects.requireNonNull(value))
when(mock.isPresent()).thenReturn(true)
return mock
}