Fix performance regressions in large multi-project builds. (#571)
* Perf improvements to multi-project builds. * Fixes. * More fixes. * Layered mappings fixes * Perf improvements. Undo broken fix. * Fix remap classpath being empty. * Another gradle bug? Either way this is fine and works. * Fix broken test * Final fixes? * Fix and cleanup mixin ap mappings.dev/0.11
parent
6fd3d5d021
commit
d40241d75a
20
build.gradle
20
build.gradle
|
@ -114,14 +114,8 @@ jar {
|
||||||
from configurations.bootstrap.collect { it.isDirectory() ? it : zipTree(it) }
|
from configurations.bootstrap.collect { it.isDirectory() ? it : zipTree(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
task sourcesJar(type: Jar, dependsOn: classes) {
|
java {
|
||||||
archiveClassifier = 'sources'
|
withSourcesJar()
|
||||||
from sourceSets.main.allSource
|
|
||||||
}
|
|
||||||
|
|
||||||
task javadocJar(type: Jar, dependsOn: javadoc) {
|
|
||||||
archiveClassifier = 'javadoc'
|
|
||||||
from javadoc.destinationDir
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spotless {
|
spotless {
|
||||||
|
@ -197,10 +191,7 @@ publishing {
|
||||||
artifactId project.archivesBaseName
|
artifactId project.archivesBaseName
|
||||||
version project.version
|
version project.version
|
||||||
|
|
||||||
from components['java']
|
from components.java
|
||||||
|
|
||||||
artifact sourcesJar
|
|
||||||
artifact javadocJar
|
|
||||||
|
|
||||||
pom.withXml {
|
pom.withXml {
|
||||||
patchPom(asNode())
|
patchPom(asNode())
|
||||||
|
@ -213,10 +204,7 @@ publishing {
|
||||||
artifactId project.archivesBaseName
|
artifactId project.archivesBaseName
|
||||||
version baseVersion + '-SNAPSHOT'
|
version baseVersion + '-SNAPSHOT'
|
||||||
|
|
||||||
from components['java']
|
from components.java
|
||||||
|
|
||||||
artifact sourcesJar
|
|
||||||
artifact javadocJar
|
|
||||||
|
|
||||||
pom.withXml {
|
pom.withXml {
|
||||||
patchPom(asNode())
|
patchPom(asNode())
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
|
|
||||||
package net.fabricmc.loom;
|
package net.fabricmc.loom;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
@ -37,7 +36,6 @@ import org.gradle.api.Project;
|
||||||
import org.gradle.api.artifacts.Configuration;
|
import org.gradle.api.artifacts.Configuration;
|
||||||
import org.gradle.api.file.ConfigurableFileCollection;
|
import org.gradle.api.file.ConfigurableFileCollection;
|
||||||
import org.gradle.api.file.FileCollection;
|
import org.gradle.api.file.FileCollection;
|
||||||
import org.gradle.api.tasks.SourceSet;
|
|
||||||
|
|
||||||
import net.fabricmc.loom.api.LoomGradleExtensionAPI;
|
import net.fabricmc.loom.api.LoomGradleExtensionAPI;
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||||
|
@ -112,10 +110,6 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI {
|
||||||
|
|
||||||
FileCollection getMinecraftJarsCollection(MappingsNamespace mappingsNamespace);
|
FileCollection getMinecraftJarsCollection(MappingsNamespace mappingsNamespace);
|
||||||
|
|
||||||
File getMixinMappings(SourceSet sourceSet);
|
|
||||||
|
|
||||||
FileCollection getAllMixinMappings();
|
|
||||||
|
|
||||||
boolean isRootProject();
|
boolean isRootProject();
|
||||||
|
|
||||||
default String getIntermediaryUrl(String minecraftVersion) {
|
default String getIntermediaryUrl(String minecraftVersion) {
|
||||||
|
|
|
@ -37,7 +37,7 @@ public abstract class DecompilerOptions implements Named {
|
||||||
/**
|
/**
|
||||||
* Class name for to the {@link LoomDecompiler}.
|
* Class name for to the {@link LoomDecompiler}.
|
||||||
*/
|
*/
|
||||||
public abstract Property<String> getDecompilerClassname();
|
public abstract Property<String> getDecompilerClassName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Additional classpath entries for the decompiler jvm.
|
* Additional classpath entries for the decompiler jvm.
|
||||||
|
@ -60,7 +60,7 @@ public abstract class DecompilerOptions implements Named {
|
||||||
public abstract Property<Integer> getMaxThreads();
|
public abstract Property<Integer> getMaxThreads();
|
||||||
|
|
||||||
public DecompilerOptions() {
|
public DecompilerOptions() {
|
||||||
getDecompilerClassname().finalizeValueOnRead();
|
getDecompilerClassName().finalizeValueOnRead();
|
||||||
getClasspath().finalizeValueOnRead();
|
getClasspath().finalizeValueOnRead();
|
||||||
getOptions().finalizeValueOnRead();
|
getOptions().finalizeValueOnRead();
|
||||||
getMemory().convention(4096L).finalizeValueOnRead();
|
getMemory().convention(4096L).finalizeValueOnRead();
|
||||||
|
@ -71,9 +71,9 @@ public abstract class DecompilerOptions implements Named {
|
||||||
public record Dto(String className, Map<String, String> options, int maxThreads) implements Serializable { }
|
public record Dto(String className, Map<String, String> options, int maxThreads) implements Serializable { }
|
||||||
|
|
||||||
public Dto toDto() {
|
public Dto toDto() {
|
||||||
Preconditions.checkArgument(getDecompilerClassname().isPresent(), "No decompiler classname specified for decompiler: " + getName());
|
Preconditions.checkArgument(getDecompilerClassName().isPresent(), "No decompiler classname specified for decompiler: " + getName());
|
||||||
return new Dto(
|
return new Dto(
|
||||||
getDecompilerClassname().get(),
|
getDecompilerClassName().get(),
|
||||||
getOptions().get(),
|
getOptions().get(),
|
||||||
getMaxThreads().get()
|
getMaxThreads().get()
|
||||||
);
|
);
|
||||||
|
|
|
@ -25,13 +25,14 @@
|
||||||
package net.fabricmc.loom.api.mappings.layered;
|
package net.fabricmc.loom.api.mappings.layered;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.gradle.api.artifacts.Dependency;
|
import org.gradle.api.artifacts.Dependency;
|
||||||
import org.gradle.api.logging.Logger;
|
import org.gradle.api.logging.Logger;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider;
|
|
||||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||||
|
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||||
|
|
||||||
@ApiStatus.Experimental /* Very Experimental and not cleanly separated from the impl atm */
|
@ApiStatus.Experimental /* Very Experimental and not cleanly separated from the impl atm */
|
||||||
public interface MappingContext {
|
public interface MappingContext {
|
||||||
|
@ -39,7 +40,7 @@ public interface MappingContext {
|
||||||
|
|
||||||
Path resolveMavenDependency(String mavenNotation);
|
Path resolveMavenDependency(String mavenNotation);
|
||||||
|
|
||||||
MappingsProvider mappingsProvider();
|
Supplier<MemoryMappingTree> intermediaryTree();
|
||||||
|
|
||||||
MinecraftProvider minecraftProvider();
|
MinecraftProvider minecraftProvider();
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ import org.gradle.api.tasks.SourceSet;
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.configuration.ide.idea.IdeaUtils;
|
import net.fabricmc.loom.configuration.ide.idea.IdeaUtils;
|
||||||
import net.fabricmc.loom.extension.MixinExtension;
|
import net.fabricmc.loom.extension.MixinExtension;
|
||||||
|
import net.fabricmc.loom.task.service.MixinMappingsService;
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,7 +85,7 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
|
||||||
String refmapName = Objects.requireNonNull(MixinExtension.getMixinInformationContainer(sourceSet)).refmapNameProvider().get();
|
String refmapName = Objects.requireNonNull(MixinExtension.getMixinInformationContainer(sourceSet)).refmapNameProvider().get();
|
||||||
Map<String, String> args = new HashMap<>() {{
|
Map<String, String> args = new HashMap<>() {{
|
||||||
put(Constants.MixinArguments.IN_MAP_FILE_NAMED_INTERMEDIARY, loom.getMappingsProvider().tinyMappings.toFile().getCanonicalPath());
|
put(Constants.MixinArguments.IN_MAP_FILE_NAMED_INTERMEDIARY, loom.getMappingsProvider().tinyMappings.toFile().getCanonicalPath());
|
||||||
put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, loom.getMixinMappings(sourceSet).getCanonicalPath());
|
put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, MixinMappingsService.getMixinMappingFile(project, sourceSet).getCanonicalPath());
|
||||||
put(Constants.MixinArguments.OUT_REFMAP_FILE, getRefmapDestination(task, refmapName));
|
put(Constants.MixinArguments.OUT_REFMAP_FILE, getRefmapDestination(task, refmapName));
|
||||||
put(Constants.MixinArguments.DEFAULT_OBFUSCATION_ENV, "named:intermediary");
|
put(Constants.MixinArguments.DEFAULT_OBFUSCATION_ENV, "named:intermediary");
|
||||||
}};
|
}};
|
||||||
|
|
|
@ -193,15 +193,15 @@ public final class CompileConfiguration {
|
||||||
|
|
||||||
boolean split = project.getProperties().get("fabric.loom.experimental.splitMcJars") != null;
|
boolean split = project.getProperties().get("fabric.loom.experimental.splitMcJars") != null;
|
||||||
|
|
||||||
// Provide the vanilla mc jars
|
// Provide the vanilla mc jars -- TODO share across projects.
|
||||||
final MinecraftProvider minecraftProvider = split ? new SplitMinecraftProvider(project) : new MergedMinecraftProvider(project);
|
final MinecraftProvider minecraftProvider = split ? new SplitMinecraftProvider(project) : new MergedMinecraftProvider(project);
|
||||||
extension.setMinecraftProvider(minecraftProvider);
|
extension.setMinecraftProvider(minecraftProvider);
|
||||||
minecraftProvider.provide();
|
minecraftProvider.provide();
|
||||||
|
|
||||||
// Provide the mappings
|
final DependencyInfo mappingsDep = DependencyInfo.create(project, Constants.Configurations.MAPPINGS);
|
||||||
final MappingsProviderImpl mappingsProvider = new MappingsProviderImpl(project, minecraftProvider);
|
final MappingsProviderImpl mappingsProvider = MappingsProviderImpl.getInstance(project, mappingsDep, minecraftProvider);
|
||||||
extension.setMappingsProvider(mappingsProvider);
|
extension.setMappingsProvider(mappingsProvider);
|
||||||
mappingsProvider.provide();
|
mappingsProvider.applyToProject(project, mappingsDep);
|
||||||
|
|
||||||
// Provide the remapped mc jars
|
// Provide the remapped mc jars
|
||||||
final IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider;
|
final IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider;
|
||||||
|
|
|
@ -26,6 +26,7 @@ package net.fabricmc.loom.configuration.providers.mappings;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
import org.gradle.api.artifacts.Configuration;
|
import org.gradle.api.artifacts.Configuration;
|
||||||
|
@ -36,6 +37,7 @@ import org.gradle.api.logging.Logger;
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingContext;
|
import net.fabricmc.loom.api.mappings.layered.MappingContext;
|
||||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||||
|
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||||
|
|
||||||
public class GradleMappingContext implements MappingContext {
|
public class GradleMappingContext implements MappingContext {
|
||||||
private final Project project;
|
private final Project project;
|
||||||
|
@ -62,8 +64,8 @@ public class GradleMappingContext implements MappingContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MappingsProvider mappingsProvider() {
|
public Supplier<MemoryMappingTree> intermediaryTree() {
|
||||||
return extension.getMappingsProvider();
|
return () -> IntermediaryService.getInstance(project, minecraftProvider()).getMemoryMappingTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* 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.configuration.providers.mappings;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.net.URL;
|
||||||
|
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 com.google.common.net.UrlEscapers;
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.jetbrains.annotations.VisibleForTesting;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
|
import net.fabricmc.loom.LoomGradlePlugin;
|
||||||
|
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||||
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||||
|
import net.fabricmc.loom.util.DownloadUtil;
|
||||||
|
import net.fabricmc.loom.util.service.SharedService;
|
||||||
|
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||||
|
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
|
||||||
|
import net.fabricmc.mappingio.format.Tiny2Reader;
|
||||||
|
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||||
|
|
||||||
|
public final class IntermediaryService implements SharedService {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(IntermediaryService.class);
|
||||||
|
|
||||||
|
private final Path intermediaryTiny;
|
||||||
|
private final Supplier<MemoryMappingTree> memoryMappingTree = Suppliers.memoize(this::createMemoryMappingTree);
|
||||||
|
|
||||||
|
private IntermediaryService(Path intermediaryTiny) {
|
||||||
|
this.intermediaryTiny = intermediaryTiny;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized IntermediaryService getInstance(Project project, MinecraftProvider minecraftProvider) {
|
||||||
|
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||||
|
final String encodedMinecraftVersion = UrlEscapers.urlFragmentEscaper().escape(minecraftProvider.minecraftVersion());
|
||||||
|
final String intermediaryArtifactUrl = extension.getIntermediaryUrl(encodedMinecraftVersion);
|
||||||
|
|
||||||
|
return SharedServiceManager.get(project).getOrCreateService("IntermediaryService:" + intermediaryArtifactUrl,
|
||||||
|
() -> create(intermediaryArtifactUrl, minecraftProvider));
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public static IntermediaryService create(String intermediaryUrl, MinecraftProvider minecraftProvider) {
|
||||||
|
final Path intermediaryTiny = minecraftProvider.file("intermediary-v2.tiny").toPath();
|
||||||
|
|
||||||
|
if (!Files.exists(intermediaryTiny) || LoomGradlePlugin.refreshDeps) {
|
||||||
|
// Download and extract intermediary
|
||||||
|
File intermediaryJar = minecraftProvider.file("intermediary-v2.jar");
|
||||||
|
|
||||||
|
try {
|
||||||
|
DownloadUtil.downloadIfChanged(new URL(intermediaryUrl), intermediaryJar, LOGGER);
|
||||||
|
MappingsProviderImpl.extractMappings(intermediaryJar.toPath(), intermediaryTiny);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException("Failed to download and extract intermediary", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new IntermediaryService(intermediaryTiny);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MemoryMappingTree createMemoryMappingTree() {
|
||||||
|
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)) {
|
||||||
|
Tiny2Reader.read(reader, nsCompleter);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException("Failed to read intermediary mappings", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemoryMappingTree getMemoryMappingTree() {
|
||||||
|
return memoryMappingTree.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path getIntermediaryTiny() {
|
||||||
|
return Objects.requireNonNull(intermediaryTiny, "Intermediary mappings have not been setup");
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,107 +28,135 @@ import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.net.URL;
|
import java.io.UncheckedIOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.FileSystem;
|
import java.nio.file.FileSystem;
|
||||||
import java.nio.file.FileSystems;
|
import java.nio.file.FileSystems;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.regex.Pattern;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import com.google.common.base.Stopwatch;
|
import com.google.common.base.Suppliers;
|
||||||
import com.google.common.net.UrlEscapers;
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import org.apache.tools.ant.util.StringUtils;
|
import org.apache.tools.ant.util.StringUtils;
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
|
||||||
import net.fabricmc.loom.LoomGradlePlugin;
|
import net.fabricmc.loom.LoomGradlePlugin;
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
|
||||||
import net.fabricmc.loom.configuration.DependencyInfo;
|
import net.fabricmc.loom.configuration.DependencyInfo;
|
||||||
|
import net.fabricmc.loom.configuration.providers.mappings.tiny.MappingsMerger;
|
||||||
|
import net.fabricmc.loom.configuration.providers.mappings.tiny.TinyJarInfo;
|
||||||
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
import net.fabricmc.loom.util.DeletingFileVisitor;
|
import net.fabricmc.loom.util.DeletingFileVisitor;
|
||||||
import net.fabricmc.loom.util.DownloadUtil;
|
|
||||||
import net.fabricmc.loom.util.ZipUtils;
|
import net.fabricmc.loom.util.ZipUtils;
|
||||||
|
import net.fabricmc.loom.util.service.SharedService;
|
||||||
|
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||||
import net.fabricmc.mappingio.MappingReader;
|
import net.fabricmc.mappingio.MappingReader;
|
||||||
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
|
|
||||||
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
|
|
||||||
import net.fabricmc.mappingio.format.MappingFormat;
|
import net.fabricmc.mappingio.format.MappingFormat;
|
||||||
import net.fabricmc.mappingio.format.Tiny2Reader;
|
|
||||||
import net.fabricmc.mappingio.format.Tiny2Writer;
|
|
||||||
import net.fabricmc.mappingio.tree.MappingTree;
|
|
||||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||||
import net.fabricmc.stitch.Command;
|
import net.fabricmc.stitch.Command;
|
||||||
import net.fabricmc.stitch.commands.CommandProposeFieldNames;
|
import net.fabricmc.stitch.commands.CommandProposeFieldNames;
|
||||||
|
|
||||||
public class MappingsProviderImpl implements MappingsProvider {
|
public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||||
public String mappingsIdentifier;
|
private static final Logger LOGGER = LoggerFactory.getLogger(MappingsProviderImpl.class);
|
||||||
|
|
||||||
private Path mappingsWorkingDir;
|
private Supplier<MemoryMappingTree> mappingTree;
|
||||||
private Path intermediaryTiny;
|
public final String mappingsIdentifier;
|
||||||
private boolean hasRefreshed = false;
|
|
||||||
|
private final Path mappingsWorkingDir;
|
||||||
// The mappings that gradle gives us
|
// The mappings that gradle gives us
|
||||||
private Path baseTinyMappings;
|
private final Path baseTinyMappings;
|
||||||
// The mappings we use in practice
|
// The mappings we use in practice
|
||||||
public Path tinyMappings;
|
public final Path tinyMappings;
|
||||||
public Path tinyMappingsJar;
|
public final Path tinyMappingsJar;
|
||||||
private Path unpickDefinitions;
|
private final Path unpickDefinitions;
|
||||||
|
|
||||||
private boolean hasUnpickDefinitions;
|
private boolean hasUnpickDefinitions;
|
||||||
private UnpickMetadata unpickMetadata;
|
private UnpickMetadata unpickMetadata;
|
||||||
private MemoryMappingTree mappingTree;
|
|
||||||
private Map<String, String> signatureFixes;
|
private Map<String, String> signatureFixes;
|
||||||
|
|
||||||
private final Project project;
|
private final Supplier<IntermediaryService> intermediaryService;
|
||||||
private final MinecraftProvider minecraftProvider;
|
|
||||||
private final LoomGradleExtension extension;
|
private MappingsProviderImpl(String mappingsIdentifier, Path mappingsWorkingDir, Supplier<IntermediaryService> intermediaryService) {
|
||||||
public MappingsProviderImpl(Project project, MinecraftProvider minecraftProvider) {
|
this.mappingsIdentifier = mappingsIdentifier;
|
||||||
this.project = project;
|
|
||||||
this.minecraftProvider = minecraftProvider;
|
this.mappingsWorkingDir = mappingsWorkingDir;
|
||||||
this.extension = LoomGradleExtension.get(project);
|
this.baseTinyMappings = mappingsWorkingDir.resolve("mappings-base.tiny");
|
||||||
|
this.tinyMappings = mappingsWorkingDir.resolve("mappings.tiny");
|
||||||
|
this.tinyMappingsJar = mappingsWorkingDir.resolve("mappings.jar");
|
||||||
|
this.unpickDefinitions = mappingsWorkingDir.resolve("mappings.unpick");
|
||||||
|
|
||||||
|
this.intermediaryService = intermediaryService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized MappingsProviderImpl getInstance(Project project, DependencyInfo dependency, MinecraftProvider minecraftProvider) {
|
||||||
|
return SharedServiceManager.get(project).getOrCreateService("MappingsProvider:%s:%s".formatted(dependency.getDepString(), minecraftProvider.minecraftVersion()), () -> {
|
||||||
|
Supplier<IntermediaryService> intermediaryService = Suppliers.memoize(() -> IntermediaryService.getInstance(project, minecraftProvider));
|
||||||
|
return create(dependency, minecraftProvider, intermediaryService);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public MemoryMappingTree getMappings() throws IOException {
|
public MemoryMappingTree getMappings() throws IOException {
|
||||||
return Objects.requireNonNull(mappingTree, "Cannot get mappings before they have been read");
|
return Objects.requireNonNull(mappingTree, "Cannot get mappings before they have been read").get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void provide() throws Exception {
|
private static MappingsProviderImpl create(DependencyInfo dependency, MinecraftProvider minecraftProvider, Supplier<IntermediaryService> intermediaryService) {
|
||||||
final DependencyInfo dependency = DependencyInfo.create(project, Constants.Configurations.MAPPINGS);
|
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");
|
||||||
|
|
||||||
project.getLogger().info(":setting up mappings (" + dependency.getDependency().getName() + " " + dependency.getResolvedVersion() + ")");
|
final TinyJarInfo jarInfo = TinyJarInfo.get(inputJar);
|
||||||
|
jarInfo.minecraftVersionId().ifPresent(id -> {
|
||||||
|
if (!minecraftProvider.minecraftVersion().equals(id)) {
|
||||||
|
LOGGER.warn("The mappings (%s) were not build for minecraft version (%s) produce with caution.".formatted(dependency.getDepString(), minecraftProvider.minecraftVersion()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
String version = dependency.getResolvedVersion();
|
final String mappingsIdentifier = createMappingsIdentifier(mappingsName, version, getMappingsClassifier(dependency, jarInfo.v2()), minecraftProvider.minecraftVersion());
|
||||||
File mappingsJar = dependency.resolveFile().orElseThrow(() -> new RuntimeException("Could not find yarn mappings: " + dependency));
|
final Path workingDir = minecraftProvider.dir(mappingsIdentifier).toPath();
|
||||||
|
|
||||||
String mappingsName = StringUtils.removeSuffix(dependency.getDependency().getGroup() + "." + dependency.getDependency().getName(), "-unmerged");
|
var mappingProvider = new MappingsProviderImpl(mappingsIdentifier, workingDir, intermediaryService);
|
||||||
boolean isV2 = isV2(dependency, mappingsJar);
|
|
||||||
this.mappingsIdentifier = createMappingsIdentifier(mappingsName, version, getMappingsClassifier(dependency, isV2));
|
|
||||||
|
|
||||||
initFiles();
|
try {
|
||||||
|
mappingProvider.setup(minecraftProvider, inputJar);
|
||||||
|
} catch (IOException e) {
|
||||||
|
cleanWorkingDirectory(workingDir);
|
||||||
|
throw new UncheckedIOException("Failed to setup mappings: " + dependency.getDepString(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mappingProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setup(MinecraftProvider minecraftProvider, Path inputJar) throws IOException {
|
||||||
|
if (isRefreshDeps()) {
|
||||||
|
cleanWorkingDirectory(mappingsWorkingDir);
|
||||||
|
}
|
||||||
|
|
||||||
if (Files.notExists(tinyMappings) || isRefreshDeps()) {
|
if (Files.notExists(tinyMappings) || isRefreshDeps()) {
|
||||||
storeMappings(project, minecraftProvider, mappingsJar.toPath());
|
storeMappings(minecraftProvider, inputJar);
|
||||||
} else {
|
} else {
|
||||||
try (FileSystem fileSystem = FileSystems.newFileSystem(mappingsJar.toPath(), (ClassLoader) null)) {
|
try (FileSystem fileSystem = FileSystems.newFileSystem(inputJar, (ClassLoader) null)) {
|
||||||
extractExtras(fileSystem);
|
extractExtras(fileSystem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mappingTree = readMappings();
|
|
||||||
|
|
||||||
if (Files.notExists(tinyMappingsJar) || isRefreshDeps()) {
|
if (Files.notExists(tinyMappingsJar) || isRefreshDeps()) {
|
||||||
Files.deleteIfExists(tinyMappingsJar);
|
Files.deleteIfExists(tinyMappingsJar);
|
||||||
ZipUtils.add(tinyMappingsJar, "mappings/mappings.tiny", Files.readAllBytes(tinyMappings));
|
ZipUtils.add(tinyMappingsJar, "mappings/mappings.tiny", Files.readAllBytes(tinyMappings));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mappingTree = Suppliers.memoize(this::readMappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyToProject(Project project, DependencyInfo dependency) {
|
||||||
if (hasUnpickDefinitions()) {
|
if (hasUnpickDefinitions()) {
|
||||||
String notation = String.format("%s:%s:%s:constants",
|
String notation = String.format("%s:%s:%s:constants",
|
||||||
dependency.getDependency().getGroup(),
|
dependency.getDependency().getGroup(),
|
||||||
|
@ -137,13 +165,13 @@ public class MappingsProviderImpl implements MappingsProvider {
|
||||||
);
|
);
|
||||||
|
|
||||||
project.getDependencies().add(Constants.Configurations.MAPPING_CONSTANTS, notation);
|
project.getDependencies().add(Constants.Configurations.MAPPING_CONSTANTS, notation);
|
||||||
populateUnpickClasspath();
|
populateUnpickClasspath(project);
|
||||||
}
|
}
|
||||||
|
|
||||||
project.getDependencies().add(Constants.Configurations.MAPPINGS_FINAL, project.files(tinyMappingsJar.toFile()));
|
project.getDependencies().add(Constants.Configurations.MAPPINGS_FINAL, project.files(tinyMappingsJar.toFile()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getMappingsClassifier(DependencyInfo dependency, boolean isV2) {
|
private static String getMappingsClassifier(DependencyInfo dependency, boolean isV2) {
|
||||||
String[] depStringSplit = dependency.getDepString().split(":");
|
String[] depStringSplit = dependency.getDepString().split(":");
|
||||||
|
|
||||||
if (depStringSplit.length >= 4) {
|
if (depStringSplit.length >= 4) {
|
||||||
|
@ -153,42 +181,22 @@ public class MappingsProviderImpl implements MappingsProvider {
|
||||||
return isV2 ? "-v2" : "";
|
return isV2 ? "-v2" : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isV2(DependencyInfo dependency, File mappingsJar) throws IOException {
|
private void storeMappings(MinecraftProvider minecraftProvider, Path inputJar) throws IOException {
|
||||||
String minecraftVersion = minecraftProvider.minecraftVersion();
|
LOGGER.info(":extracting " + inputJar.getFileName());
|
||||||
|
|
||||||
// Only do this for official yarn, there isn't really a way we can get the mc version for all mappings
|
try (FileSystem fileSystem = FileSystems.newFileSystem(inputJar, (ClassLoader) null)) {
|
||||||
if (dependency.getDependency().getGroup() != null && dependency.getDependency().getGroup().equals("net.fabricmc") && dependency.getDependency().getName().equals("yarn") && dependency.getDependency().getVersion() != null) {
|
|
||||||
String yarnVersion = dependency.getDependency().getVersion();
|
|
||||||
char separator = yarnVersion.contains("+build.") ? '+' : yarnVersion.contains("-") ? '-' : '.';
|
|
||||||
String yarnMinecraftVersion = yarnVersion.substring(0, yarnVersion.lastIndexOf(separator));
|
|
||||||
|
|
||||||
if (!yarnMinecraftVersion.equalsIgnoreCase(minecraftVersion)) {
|
|
||||||
project.getLogger().warn("Minecraft Version ({}) does not match yarn's minecraft version ({})", minecraftVersion, yarnMinecraftVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can save reading the zip file + header by checking the file name
|
|
||||||
return mappingsJar.getName().endsWith("-v2.jar");
|
|
||||||
} else {
|
|
||||||
return doesJarContainV2Mappings(mappingsJar.toPath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void storeMappings(Project project, MinecraftProvider minecraftProvider, Path yarnJar) throws IOException {
|
|
||||||
project.getLogger().info(":extracting " + yarnJar.getFileName());
|
|
||||||
|
|
||||||
try (FileSystem fileSystem = FileSystems.newFileSystem(yarnJar, (ClassLoader) null)) {
|
|
||||||
extractMappings(fileSystem, baseTinyMappings);
|
extractMappings(fileSystem, baseTinyMappings);
|
||||||
extractExtras(fileSystem);
|
extractExtras(fileSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (areMappingsV2(baseTinyMappings)) {
|
if (areMappingsV2(baseTinyMappings)) {
|
||||||
// These are unmerged v2 mappings
|
// These are unmerged v2 mappings
|
||||||
mergeAndSaveMappings(project, baseTinyMappings, tinyMappings);
|
MappingsMerger.mergeAndSaveMappings(baseTinyMappings, tinyMappings, intermediaryService.get());
|
||||||
} else {
|
} else {
|
||||||
if (minecraftProvider instanceof MergedMinecraftProvider mergedMinecraftProvider) {
|
if (minecraftProvider instanceof MergedMinecraftProvider mergedMinecraftProvider) {
|
||||||
// These are merged v1 mappings
|
// These are merged v1 mappings
|
||||||
Files.deleteIfExists(tinyMappings);
|
Files.deleteIfExists(tinyMappings);
|
||||||
project.getLogger().lifecycle(":populating field names");
|
LOGGER.info(":populating field names");
|
||||||
suggestFieldNames(mergedMinecraftProvider, baseTinyMappings, tinyMappings);
|
suggestFieldNames(mergedMinecraftProvider, baseTinyMappings, tinyMappings);
|
||||||
} else {
|
} else {
|
||||||
throw new UnsupportedOperationException("V1 mappings only support merged minecraft");
|
throw new UnsupportedOperationException("V1 mappings only support merged minecraft");
|
||||||
|
@ -196,10 +204,14 @@ public class MappingsProviderImpl implements MappingsProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MemoryMappingTree readMappings() throws IOException {
|
private MemoryMappingTree readMappings() {
|
||||||
MemoryMappingTree mappingTree = new MemoryMappingTree();
|
try {
|
||||||
MappingReader.read(tinyMappings, mappingTree);
|
MemoryMappingTree mappingTree = new MemoryMappingTree();
|
||||||
return mappingTree;
|
MappingReader.read(tinyMappings, mappingTree);
|
||||||
|
return mappingTree;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException("Failed to read mappings", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean areMappingsV2(Path path) throws IOException {
|
private static boolean areMappingsV2(Path path) throws IOException {
|
||||||
|
@ -208,15 +220,7 @@ public class MappingsProviderImpl implements MappingsProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean doesJarContainV2Mappings(Path path) throws IOException {
|
public static void extractMappings(Path jar, Path extractTo) throws IOException {
|
||||||
try (FileSystem fs = FileSystems.newFileSystem(path, (ClassLoader) null)) {
|
|
||||||
try (BufferedReader reader = Files.newBufferedReader(fs.getPath("mappings", "mappings.tiny"))) {
|
|
||||||
return MappingReader.detectFormat(reader) == MappingFormat.TINY_2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void extractMappings(Path jar, Path extractTo) throws IOException {
|
|
||||||
try (FileSystem unmergedIntermediaryFs = FileSystems.newFileSystem(jar, (ClassLoader) null)) {
|
try (FileSystem unmergedIntermediaryFs = FileSystems.newFileSystem(jar, (ClassLoader) null)) {
|
||||||
extractMappings(unmergedIntermediaryFs, extractTo);
|
extractMappings(unmergedIntermediaryFs, extractTo);
|
||||||
}
|
}
|
||||||
|
@ -271,7 +275,7 @@ public class MappingsProviderImpl implements MappingsProvider {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populateUnpickClasspath() {
|
private void populateUnpickClasspath(Project project) {
|
||||||
String unpickCliName = "unpick-cli";
|
String unpickCliName = "unpick-cli";
|
||||||
project.getDependencies().add(Constants.Configurations.UNPICK_CLASSPATH,
|
project.getDependencies().add(Constants.Configurations.UNPICK_CLASSPATH,
|
||||||
String.format("%s:%s:%s", unpickMetadata.unpickGroup, unpickCliName, unpickMetadata.unpickVersion)
|
String.format("%s:%s:%s", unpickMetadata.unpickGroup, unpickCliName, unpickMetadata.unpickVersion)
|
||||||
|
@ -292,76 +296,6 @@ public class MappingsProviderImpl implements MappingsProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mergeAndSaveMappings(Project project, Path from, Path out) throws IOException {
|
|
||||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
|
||||||
project.getLogger().info(":merging mappings");
|
|
||||||
|
|
||||||
MemoryMappingTree intermediaryTree = new MemoryMappingTree();
|
|
||||||
readIntermediaryTree().accept(new MappingSourceNsSwitch(intermediaryTree, MappingsNamespace.INTERMEDIARY.toString()));
|
|
||||||
|
|
||||||
try (BufferedReader reader = Files.newBufferedReader(from, StandardCharsets.UTF_8)) {
|
|
||||||
Tiny2Reader.read(reader, intermediaryTree);
|
|
||||||
}
|
|
||||||
|
|
||||||
MemoryMappingTree officialTree = new MemoryMappingTree();
|
|
||||||
MappingNsCompleter nsCompleter = new MappingNsCompleter(officialTree, Map.of(MappingsNamespace.OFFICIAL.toString(), MappingsNamespace.INTERMEDIARY.toString()));
|
|
||||||
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(nsCompleter, MappingsNamespace.OFFICIAL.toString());
|
|
||||||
intermediaryTree.accept(nsSwitch);
|
|
||||||
|
|
||||||
inheritMappedNamesOfEnclosingClasses(officialTree);
|
|
||||||
|
|
||||||
try (Tiny2Writer writer = new Tiny2Writer(Files.newBufferedWriter(out, StandardCharsets.UTF_8), false)) {
|
|
||||||
officialTree.accept(writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
project.getLogger().info(":merged mappings in " + stopwatch.stop());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Searches the mapping tree for inner classes with no mapped name, whose enclosing classes have mapped names.
|
|
||||||
* Currently, Yarn does not export mappings for these inner classes.
|
|
||||||
*/
|
|
||||||
private void inheritMappedNamesOfEnclosingClasses(MemoryMappingTree tree) {
|
|
||||||
int intermediaryIdx = tree.getNamespaceId("intermediary");
|
|
||||||
int namedIdx = tree.getNamespaceId("named");
|
|
||||||
|
|
||||||
// The tree does not have an index by intermediary names by default
|
|
||||||
tree.setIndexByDstNames(true);
|
|
||||||
|
|
||||||
for (MappingTree.ClassMapping classEntry : tree.getClasses()) {
|
|
||||||
String intermediaryName = classEntry.getDstName(intermediaryIdx);
|
|
||||||
String namedName = classEntry.getDstName(namedIdx);
|
|
||||||
|
|
||||||
if (intermediaryName.equals(namedName) && intermediaryName.contains("$")) {
|
|
||||||
String[] path = intermediaryName.split(Pattern.quote("$"));
|
|
||||||
int parts = path.length;
|
|
||||||
|
|
||||||
for (int i = parts - 2; i >= 0; i--) {
|
|
||||||
String currentPath = String.join("$", Arrays.copyOfRange(path, 0, i + 1));
|
|
||||||
String namedParentClass = tree.mapClassName(currentPath, intermediaryIdx, namedIdx);
|
|
||||||
|
|
||||||
if (!namedParentClass.equals(currentPath)) {
|
|
||||||
classEntry.setDstName(namedParentClass
|
|
||||||
+ "$" + String.join("$", Arrays.copyOfRange(path, i + 1, path.length)),
|
|
||||||
namedIdx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private MemoryMappingTree readIntermediaryTree() throws IOException {
|
|
||||||
MemoryMappingTree tree = new MemoryMappingTree();
|
|
||||||
MappingNsCompleter nsCompleter = new MappingNsCompleter(tree, Collections.singletonMap(MappingsNamespace.NAMED.toString(), MappingsNamespace.INTERMEDIARY.toString()), true);
|
|
||||||
|
|
||||||
try (BufferedReader reader = Files.newBufferedReader(getIntermediaryTiny(), StandardCharsets.UTF_8)) {
|
|
||||||
Tiny2Reader.read(reader, nsCompleter);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void suggestFieldNames(MergedMinecraftProvider minecraftProvider, Path oldMappings, Path newMappings) {
|
private void suggestFieldNames(MergedMinecraftProvider minecraftProvider, Path oldMappings, Path newMappings) {
|
||||||
Command command = new CommandProposeFieldNames();
|
Command command = new CommandProposeFieldNames();
|
||||||
runCommand(command, minecraftProvider.getMergedJar().getAbsolutePath(),
|
runCommand(command, minecraftProvider.getMergedJar().getAbsolutePath(),
|
||||||
|
@ -377,19 +311,7 @@ public class MappingsProviderImpl implements MappingsProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initFiles() {
|
private static void cleanWorkingDirectory(Path mappingsWorkingDir) {
|
||||||
mappingsWorkingDir = minecraftProvider.dir(mappingsIdentifier).toPath();
|
|
||||||
baseTinyMappings = mappingsWorkingDir.resolve("mappings-base.tiny");
|
|
||||||
tinyMappings = mappingsWorkingDir.resolve("mappings.tiny");
|
|
||||||
tinyMappingsJar = mappingsWorkingDir.resolve("mappings.jar");
|
|
||||||
unpickDefinitions = mappingsWorkingDir.resolve("mappings.unpick");
|
|
||||||
|
|
||||||
if (isRefreshDeps()) {
|
|
||||||
cleanFiles();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cleanFiles() {
|
|
||||||
try {
|
try {
|
||||||
if (Files.exists(mappingsWorkingDir)) {
|
if (Files.exists(mappingsWorkingDir)) {
|
||||||
Files.walkFileTree(mappingsWorkingDir, new DeletingFileVisitor());
|
Files.walkFileTree(mappingsWorkingDir, new DeletingFileVisitor());
|
||||||
|
@ -401,34 +323,20 @@ public class MappingsProviderImpl implements MappingsProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path getIntermediaryTiny() throws IOException {
|
|
||||||
if (intermediaryTiny == null) {
|
|
||||||
intermediaryTiny = minecraftProvider.file("intermediary-v2.tiny").toPath();
|
|
||||||
|
|
||||||
if (!Files.exists(intermediaryTiny) || (isRefreshDeps() && !hasRefreshed)) {
|
|
||||||
hasRefreshed = true;
|
|
||||||
|
|
||||||
// Download and extract intermediary
|
|
||||||
String encodedMinecraftVersion = UrlEscapers.urlFragmentEscaper().escape(minecraftProvider.minecraftVersion());
|
|
||||||
String intermediaryArtifactUrl = extension.getIntermediaryUrl(encodedMinecraftVersion);
|
|
||||||
File intermediaryJar = minecraftProvider.file("intermediary-v2.jar");
|
|
||||||
DownloadUtil.downloadIfChanged(new URL(intermediaryArtifactUrl), intermediaryJar, project.getLogger());
|
|
||||||
extractMappings(intermediaryJar.toPath(), intermediaryTiny);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return intermediaryTiny;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Path mappingsWorkingDir() {
|
public Path mappingsWorkingDir() {
|
||||||
return mappingsWorkingDir;
|
return mappingsWorkingDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createMappingsIdentifier(String mappingsName, String version, String classifier) {
|
@Override
|
||||||
|
public File intermediaryTinyFile() {
|
||||||
|
return intermediaryService.get().getIntermediaryTiny().toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String createMappingsIdentifier(String mappingsName, String version, String classifier, String minecraftVersion) {
|
||||||
// mappingsName . mcVersion . version classifier
|
// mappingsName . mcVersion . version classifier
|
||||||
// Example: net.fabricmc.yarn . 1_16_5 . 1.16.5+build.5 -v2
|
// Example: net.fabricmc.yarn . 1_16_5 . 1.16.5+build.5 -v2
|
||||||
return mappingsName + "." + minecraftProvider.minecraftVersion().replace(' ', '_').replace('.', '_').replace('-', '_') + "." + version + classifier;
|
return mappingsName + "." + minecraftVersion.replace(' ', '_').replace('.', '_').replace('-', '_') + "." + version + classifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String mappingsIdentifier() {
|
public String mappingsIdentifier() {
|
||||||
|
@ -448,15 +356,6 @@ public class MappingsProviderImpl implements MappingsProvider {
|
||||||
return signatureFixes;
|
return signatureFixes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public File intermediaryTinyFile() {
|
|
||||||
try {
|
|
||||||
return getIntermediaryTiny().toFile();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Failed to get intermediary", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getBuildServiceName(String name, String from, String to) {
|
public String getBuildServiceName(String name, String from, String to) {
|
||||||
return "%s:%s:%s>%S".formatted(name, mappingsIdentifier(), from, to);
|
return "%s:%s:%s>%S".formatted(name, mappingsIdentifier(), from, to);
|
||||||
}
|
}
|
||||||
|
@ -464,7 +363,12 @@ public class MappingsProviderImpl implements MappingsProvider {
|
||||||
public record UnpickMetadata(String unpickGroup, String unpickVersion) {
|
public record UnpickMetadata(String unpickGroup, String unpickVersion) {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isRefreshDeps() {
|
protected static boolean isRefreshDeps() {
|
||||||
return LoomGradlePlugin.refreshDeps;
|
return LoomGradlePlugin.refreshDeps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
mappingTree = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,20 +24,17 @@
|
||||||
|
|
||||||
package net.fabricmc.loom.configuration.providers.mappings.intermediary;
|
package net.fabricmc.loom.configuration.providers.mappings.intermediary;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingLayer;
|
import net.fabricmc.loom.api.mappings.layered.MappingLayer;
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||||
import net.fabricmc.mappingio.MappingVisitor;
|
import net.fabricmc.mappingio.MappingVisitor;
|
||||||
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
|
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
|
||||||
import net.fabricmc.mappingio.format.Tiny2Reader;
|
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||||
|
|
||||||
public record IntermediaryMappingLayer(File tinyFile) implements MappingLayer {
|
public record IntermediaryMappingLayer(Supplier<MemoryMappingTree> memoryMappingTree) implements MappingLayer {
|
||||||
@Override
|
@Override
|
||||||
public MappingsNamespace getSourceNamespace() {
|
public MappingsNamespace getSourceNamespace() {
|
||||||
return MappingsNamespace.OFFICIAL;
|
return MappingsNamespace.OFFICIAL;
|
||||||
|
@ -48,8 +45,6 @@ public record IntermediaryMappingLayer(File tinyFile) implements MappingLayer {
|
||||||
// Populate named with intermediary and add Add a "named" namespace
|
// Populate named with intermediary and add Add a "named" namespace
|
||||||
MappingNsCompleter nsCompleter = new MappingNsCompleter(mappingVisitor, Collections.singletonMap(MappingsNamespace.NAMED.toString(), MappingsNamespace.INTERMEDIARY.toString()), true);
|
MappingNsCompleter nsCompleter = new MappingNsCompleter(mappingVisitor, Collections.singletonMap(MappingsNamespace.NAMED.toString(), MappingsNamespace.INTERMEDIARY.toString()), true);
|
||||||
|
|
||||||
try (BufferedReader reader = Files.newBufferedReader(tinyFile().toPath(), StandardCharsets.UTF_8)) {
|
memoryMappingTree.get().accept(nsCompleter);
|
||||||
Tiny2Reader.read(reader, nsCompleter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,6 @@ import net.fabricmc.loom.api.mappings.layered.spec.MappingsSpec;
|
||||||
public record IntermediaryMappingsSpec() implements MappingsSpec<IntermediaryMappingLayer> {
|
public record IntermediaryMappingsSpec() implements MappingsSpec<IntermediaryMappingLayer> {
|
||||||
@Override
|
@Override
|
||||||
public IntermediaryMappingLayer createLayer(MappingContext context) {
|
public IntermediaryMappingLayer createLayer(MappingContext context) {
|
||||||
return new IntermediaryMappingLayer(context.mappingsProvider().intermediaryTinyFile());
|
return new IntermediaryMappingLayer(context.intermediaryTree());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* 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.configuration.providers.mappings.tiny;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import com.google.common.base.Stopwatch;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||||
|
import net.fabricmc.loom.configuration.providers.mappings.IntermediaryService;
|
||||||
|
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
|
||||||
|
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
|
||||||
|
import net.fabricmc.mappingio.format.Tiny2Reader;
|
||||||
|
import net.fabricmc.mappingio.format.Tiny2Writer;
|
||||||
|
import net.fabricmc.mappingio.tree.MappingTree;
|
||||||
|
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||||
|
|
||||||
|
public final class MappingsMerger {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(MappingsMerger.class);
|
||||||
|
|
||||||
|
public static void mergeAndSaveMappings(Path from, Path out, IntermediaryService intermediaryService) throws IOException {
|
||||||
|
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||||
|
LOGGER.info(":merging mappings");
|
||||||
|
|
||||||
|
MemoryMappingTree intermediaryTree = new MemoryMappingTree();
|
||||||
|
intermediaryService.getMemoryMappingTree().accept(new MappingSourceNsSwitch(intermediaryTree, MappingsNamespace.INTERMEDIARY.toString()));
|
||||||
|
|
||||||
|
try (BufferedReader reader = Files.newBufferedReader(from, StandardCharsets.UTF_8)) {
|
||||||
|
Tiny2Reader.read(reader, intermediaryTree);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryMappingTree officialTree = new MemoryMappingTree();
|
||||||
|
MappingNsCompleter nsCompleter = new MappingNsCompleter(officialTree, Map.of(MappingsNamespace.OFFICIAL.toString(), MappingsNamespace.INTERMEDIARY.toString()));
|
||||||
|
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(nsCompleter, MappingsNamespace.OFFICIAL.toString());
|
||||||
|
intermediaryTree.accept(nsSwitch);
|
||||||
|
|
||||||
|
inheritMappedNamesOfEnclosingClasses(officialTree);
|
||||||
|
|
||||||
|
try (Tiny2Writer writer = new Tiny2Writer(Files.newBufferedWriter(out, StandardCharsets.UTF_8), false)) {
|
||||||
|
officialTree.accept(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.info(":merged mappings in " + stopwatch.stop());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches the mapping tree for inner classes with no mapped name, whose enclosing classes have mapped names.
|
||||||
|
* Currently, Yarn does not export mappings for these inner classes.
|
||||||
|
*/
|
||||||
|
private static void inheritMappedNamesOfEnclosingClasses(MemoryMappingTree tree) {
|
||||||
|
int intermediaryIdx = tree.getNamespaceId("intermediary");
|
||||||
|
int namedIdx = tree.getNamespaceId("named");
|
||||||
|
|
||||||
|
// The tree does not have an index by intermediary names by default
|
||||||
|
tree.setIndexByDstNames(true);
|
||||||
|
|
||||||
|
for (MappingTree.ClassMapping classEntry : tree.getClasses()) {
|
||||||
|
String intermediaryName = classEntry.getDstName(intermediaryIdx);
|
||||||
|
String namedName = classEntry.getDstName(namedIdx);
|
||||||
|
|
||||||
|
if (intermediaryName.equals(namedName) && intermediaryName.contains("$")) {
|
||||||
|
String[] path = intermediaryName.split(Pattern.quote("$"));
|
||||||
|
int parts = path.length;
|
||||||
|
|
||||||
|
for (int i = parts - 2; i >= 0; i--) {
|
||||||
|
String currentPath = String.join("$", Arrays.copyOfRange(path, 0, i + 1));
|
||||||
|
String namedParentClass = tree.mapClassName(currentPath, intermediaryIdx, namedIdx);
|
||||||
|
|
||||||
|
if (!namedParentClass.equals(currentPath)) {
|
||||||
|
classEntry.setDstName(namedParentClass
|
||||||
|
+ "$" + String.join("$", Arrays.copyOfRange(path, i + 1, path.length)),
|
||||||
|
namedIdx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* 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.configuration.providers.mappings.tiny;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.nio.file.FileSystem;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import net.fabricmc.mappingio.MappingReader;
|
||||||
|
import net.fabricmc.mappingio.format.MappingFormat;
|
||||||
|
|
||||||
|
public record TinyJarInfo(boolean v2, Optional<String> minecraftVersionId) {
|
||||||
|
public static TinyJarInfo get(Path jar) {
|
||||||
|
try {
|
||||||
|
return new TinyJarInfo(doesJarContainV2Mappings(jar), Optional.empty());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException("Failed to read tiny jar info", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean doesJarContainV2Mappings(Path path) throws IOException {
|
||||||
|
try (FileSystem fs = FileSystems.newFileSystem(path, (ClassLoader) null)) {
|
||||||
|
try (BufferedReader reader = Files.newBufferedReader(fs.getPath("mappings", "mappings.tiny"))) {
|
||||||
|
return MappingReader.detectFormat(reader) == MappingFormat.TINY_2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,6 +41,6 @@ public final class DecompilerConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void registerDecompiler(Project project, String name, Class<? extends LoomDecompiler> decompilerClass) {
|
private static void registerDecompiler(Project project, String name, Class<? extends LoomDecompiler> decompilerClass) {
|
||||||
LoomGradleExtension.get(project).getDecompilerOptions().register(name, options -> options.getDecompilerClassname().set(decompilerClass.getName()));
|
LoomGradleExtension.get(project).getDecompilerOptions().register(name, options -> options.getDecompilerClassName().set(decompilerClass.getName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
|
|
||||||
package net.fabricmc.loom.extension;
|
package net.fabricmc.loom.extension;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -41,7 +40,6 @@ import org.gradle.api.Project;
|
||||||
import org.gradle.api.artifacts.Configuration;
|
import org.gradle.api.artifacts.Configuration;
|
||||||
import org.gradle.api.file.ConfigurableFileCollection;
|
import org.gradle.api.file.ConfigurableFileCollection;
|
||||||
import org.gradle.api.file.FileCollection;
|
import org.gradle.api.file.FileCollection;
|
||||||
import org.gradle.api.tasks.SourceSet;
|
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||||
|
@ -60,7 +58,6 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||||
private final LoomFiles loomFiles;
|
private final LoomFiles loomFiles;
|
||||||
private final ConfigurableFileCollection unmappedMods;
|
private final ConfigurableFileCollection unmappedMods;
|
||||||
|
|
||||||
private final ConfigurableFileCollection mixinMappings;
|
|
||||||
private final MappingSet[] srcMappingCache = new MappingSet[2];
|
private final MappingSet[] srcMappingCache = new MappingSet[2];
|
||||||
private final Mercury[] srcMercuryCache = new Mercury[2];
|
private final Mercury[] srcMercuryCache = new Mercury[2];
|
||||||
private final Map<String, NamedDomainObjectProvider<Configuration>> lazyConfigurations = new HashMap<>();
|
private final Map<String, NamedDomainObjectProvider<Configuration>> lazyConfigurations = new HashMap<>();
|
||||||
|
@ -79,7 +76,6 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||||
this.project = project;
|
this.project = project;
|
||||||
// Initiate with newInstance to allow gradle to decorate our extension
|
// Initiate with newInstance to allow gradle to decorate our extension
|
||||||
this.mixinApExtension = project.getObjects().newInstance(MixinExtensionImpl.class, project);
|
this.mixinApExtension = project.getObjects().newInstance(MixinExtensionImpl.class, project);
|
||||||
this.mixinMappings = project.getObjects().fileCollection();
|
|
||||||
this.loomFiles = files;
|
this.loomFiles = files;
|
||||||
this.unmappedMods = project.files();
|
this.unmappedMods = project.files();
|
||||||
}
|
}
|
||||||
|
@ -94,18 +90,6 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||||
return loomFiles;
|
return loomFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized File getMixinMappings(SourceSet sourceSet) {
|
|
||||||
File mixinMapping = new File(getFiles().getProjectBuildCache(), "mixin-map-" + getMappingsProvider().mappingsIdentifier() + "." + sourceSet.getName() + ".tiny");
|
|
||||||
mixinMappings.from(getProject().files(mixinMapping));
|
|
||||||
return mixinMapping;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FileCollection getAllMixinMappings() {
|
|
||||||
return mixinMappings.filter(File::exists);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setDependencyManager(LoomDependencyManager dependencyManager) {
|
public void setDependencyManager(LoomDependencyManager dependencyManager) {
|
||||||
this.dependencyManager = dependencyManager;
|
this.dependencyManager = dependencyManager;
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.task;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.gradle.api.file.RegularFileProperty;
|
||||||
|
import org.gradle.api.provider.Property;
|
||||||
|
import org.gradle.api.tasks.InputFile;
|
||||||
|
import org.gradle.api.tasks.TaskAction;
|
||||||
|
import org.gradle.workers.WorkAction;
|
||||||
|
import org.gradle.workers.WorkParameters;
|
||||||
|
import org.gradle.workers.WorkQueue;
|
||||||
|
import org.gradle.workers.WorkerExecutor;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.task.service.TinyRemapperService;
|
||||||
|
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
|
||||||
|
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The prepare remap task runs before all other jar remap tasks, should be used to setup tiny remapper.
|
||||||
|
*/
|
||||||
|
public abstract class PrepareJarRemapTask extends AbstractLoomTask {
|
||||||
|
private final RemapJarTask remapJarTask;
|
||||||
|
@InputFile
|
||||||
|
public abstract RegularFileProperty getInputFile();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public PrepareJarRemapTask(RemapJarTask remapJarTask) {
|
||||||
|
this.remapJarTask = remapJarTask;
|
||||||
|
|
||||||
|
getInputFile().set(remapJarTask.getInputFile());
|
||||||
|
// TODO can this be up-to-date when the main task is up-to date?
|
||||||
|
getOutputs().upToDateWhen((o) -> false);
|
||||||
|
|
||||||
|
getProject().getGradle().allprojects(project -> {
|
||||||
|
project.getTasks().configureEach(task -> {
|
||||||
|
if (task instanceof PrepareJarRemapTask otherTask) {
|
||||||
|
if (otherTask == this) return;
|
||||||
|
|
||||||
|
// Ensure that all other prepare tasks inputs have completed
|
||||||
|
dependsOn(otherTask.getInputs());
|
||||||
|
mustRunAfter(otherTask.getInputs());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected abstract WorkerExecutor getWorkerExecutor();
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
public void run() {
|
||||||
|
final WorkQueue workQueue = getWorkerExecutor().noIsolation();
|
||||||
|
|
||||||
|
workQueue.submit(ReadInputsAction.class, params -> {
|
||||||
|
params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(getProject(), remapJarTask.getTinyRemapperService()));
|
||||||
|
params.getInputTagName().set(remapJarTask.getInputTagName());
|
||||||
|
params.getInputFile().set(getInputFile());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ReadInputsParams extends WorkParameters {
|
||||||
|
Property<String> getTinyRemapperBuildServiceUuid();
|
||||||
|
Property<String> getInputTagName();
|
||||||
|
RegularFileProperty getInputFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class ReadInputsAction implements WorkAction<ReadInputsParams> {
|
||||||
|
private final TinyRemapperService tinyRemapperService;
|
||||||
|
|
||||||
|
public ReadInputsAction() {
|
||||||
|
this.tinyRemapperService = UnsafeWorkQueueHelper.get(getParameters().getTinyRemapperBuildServiceUuid(), TinyRemapperService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
final TinyRemapper tinyRemapper = tinyRemapperService.getTinyRemapperForInputs();
|
||||||
|
final Path inputFile = getParameters().getInputFile().getAsFile().get().toPath();
|
||||||
|
|
||||||
|
tinyRemapper.readInputsAsync(tinyRemapperService.createTag(getParameters().getInputTagName().get()), inputFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,7 +26,6 @@ package net.fabricmc.loom.task;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
@ -34,12 +33,14 @@ import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.jar.Manifest;
|
import java.util.jar.Manifest;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import org.gradle.api.artifacts.Configuration;
|
import org.gradle.api.artifacts.Configuration;
|
||||||
import org.gradle.api.file.ConfigurableFileCollection;
|
import org.gradle.api.file.ConfigurableFileCollection;
|
||||||
|
@ -47,12 +48,11 @@ import org.gradle.api.file.FileCollection;
|
||||||
import org.gradle.api.plugins.JavaPlugin;
|
import org.gradle.api.plugins.JavaPlugin;
|
||||||
import org.gradle.api.provider.ListProperty;
|
import org.gradle.api.provider.ListProperty;
|
||||||
import org.gradle.api.provider.Property;
|
import org.gradle.api.provider.Property;
|
||||||
import org.gradle.api.provider.Provider;
|
|
||||||
import org.gradle.api.tasks.Input;
|
import org.gradle.api.tasks.Input;
|
||||||
import org.gradle.api.tasks.InputFiles;
|
import org.gradle.api.tasks.InputFiles;
|
||||||
|
import org.gradle.api.tasks.Internal;
|
||||||
import org.gradle.api.tasks.SourceSet;
|
import org.gradle.api.tasks.SourceSet;
|
||||||
import org.gradle.api.tasks.TaskAction;
|
import org.gradle.api.tasks.TaskAction;
|
||||||
import org.objectweb.asm.commons.Remapper;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -60,20 +60,18 @@ import net.fabricmc.accesswidener.AccessWidenerReader;
|
||||||
import net.fabricmc.accesswidener.AccessWidenerRemapper;
|
import net.fabricmc.accesswidener.AccessWidenerRemapper;
|
||||||
import net.fabricmc.accesswidener.AccessWidenerWriter;
|
import net.fabricmc.accesswidener.AccessWidenerWriter;
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
|
||||||
import net.fabricmc.loom.build.MixinRefmapHelper;
|
import net.fabricmc.loom.build.MixinRefmapHelper;
|
||||||
import net.fabricmc.loom.build.nesting.IncludedJarFactory;
|
import net.fabricmc.loom.build.nesting.IncludedJarFactory;
|
||||||
import net.fabricmc.loom.build.nesting.JarNester;
|
import net.fabricmc.loom.build.nesting.JarNester;
|
||||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
||||||
import net.fabricmc.loom.extension.MixinExtension;
|
import net.fabricmc.loom.extension.MixinExtension;
|
||||||
import net.fabricmc.loom.task.service.JarManifestService;
|
import net.fabricmc.loom.task.service.JarManifestService;
|
||||||
import net.fabricmc.loom.task.service.MappingsService;
|
import net.fabricmc.loom.task.service.TinyRemapperService;
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
import net.fabricmc.loom.util.ZipUtils;
|
import net.fabricmc.loom.util.ZipUtils;
|
||||||
import net.fabricmc.tinyremapper.InputTag;
|
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
|
||||||
import net.fabricmc.tinyremapper.OutputConsumerPath;
|
import net.fabricmc.tinyremapper.OutputConsumerPath;
|
||||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||||
import net.fabricmc.tinyremapper.TinyUtils;
|
|
||||||
|
|
||||||
public abstract class RemapJarTask extends AbstractRemapJarTask {
|
public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||||
private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
|
private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
|
||||||
|
@ -84,6 +82,8 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||||
@Input
|
@Input
|
||||||
public abstract Property<Boolean> getAddNestedDependencies();
|
public abstract Property<Boolean> getAddNestedDependencies();
|
||||||
|
|
||||||
|
private Supplier<TinyRemapperService> tinyRemapperService = Suppliers.memoize(() -> TinyRemapperService.getOrCreate(this));
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public RemapJarTask() {
|
public RemapJarTask() {
|
||||||
super();
|
super();
|
||||||
|
@ -93,6 +93,25 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||||
|
|
||||||
Configuration includeConfiguration = getProject().getConfigurations().getByName(Constants.Configurations.INCLUDE);
|
Configuration includeConfiguration = getProject().getConfigurations().getByName(Constants.Configurations.INCLUDE);
|
||||||
getNestedJars().from(new IncludedJarFactory(getProject()).getNestedJars(includeConfiguration));
|
getNestedJars().from(new IncludedJarFactory(getProject()).getNestedJars(includeConfiguration));
|
||||||
|
|
||||||
|
setupPreparationTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupPreparationTask() {
|
||||||
|
PrepareJarRemapTask prepareJarTask = getProject().getTasks().create("prepare" + getName().substring(0, 1).toUpperCase() + getName().substring(1), PrepareJarRemapTask.class, this);
|
||||||
|
|
||||||
|
dependsOn(prepareJarTask);
|
||||||
|
mustRunAfter(prepareJarTask);
|
||||||
|
|
||||||
|
getProject().getGradle().allprojects(project -> {
|
||||||
|
project.getTasks().configureEach(task -> {
|
||||||
|
if (task instanceof PrepareJarRemapTask otherTask) {
|
||||||
|
// Ensure that all remap jars run after all prepare tasks
|
||||||
|
dependsOn(otherTask);
|
||||||
|
mustRunAfter(otherTask);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
|
@ -105,14 +124,14 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
params.getJarManifestService().set(JarManifestService.get(getProject()));
|
params.getJarManifestService().set(JarManifestService.get(getProject()));
|
||||||
|
params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(getProject(), tinyRemapperService.get()));
|
||||||
params.getRemapClasspath().from(getClasspath());
|
params.getRemapClasspath().from(getClasspath());
|
||||||
params.getMappings().add(MappingsService.createDefault(getProject(), getSourceNamespace().get(), getTargetNamespace().get()));
|
params.getInputTagName().set(getInputTagName());
|
||||||
|
|
||||||
final boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get();
|
final boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get();
|
||||||
params.getUseMixinExtension().set(!legacyMixin);
|
params.getUseMixinExtension().set(!legacyMixin);
|
||||||
|
|
||||||
if (legacyMixin) {
|
if (legacyMixin) {
|
||||||
params.getMixinMappings().from(extension.getAllMixinMappings());
|
|
||||||
setupLegacyMixinRefmapRemapping(params);
|
setupLegacyMixinRefmapRemapping(params);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -174,8 +193,7 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||||
public interface RemapParams extends AbstractRemapParams {
|
public interface RemapParams extends AbstractRemapParams {
|
||||||
ConfigurableFileCollection getNestedJars();
|
ConfigurableFileCollection getNestedJars();
|
||||||
ConfigurableFileCollection getRemapClasspath();
|
ConfigurableFileCollection getRemapClasspath();
|
||||||
ConfigurableFileCollection getMixinMappings();
|
Property<String> getInputTagName();
|
||||||
ListProperty<Provider<MappingsService>> getMappings();
|
|
||||||
|
|
||||||
Property<Boolean> getUseMixinExtension();
|
Property<Boolean> getUseMixinExtension();
|
||||||
|
|
||||||
|
@ -183,19 +201,25 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||||
ListProperty<RefmapData> getMixinData();
|
ListProperty<RefmapData> getMixinData();
|
||||||
|
|
||||||
Property<JarManifestService> getJarManifestService();
|
Property<JarManifestService> getJarManifestService();
|
||||||
|
Property<String> getTinyRemapperBuildServiceUuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract static class RemapAction extends AbstractRemapAction<RemapParams> {
|
public abstract static class RemapAction extends AbstractRemapAction<RemapParams> {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(RemapAction.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(RemapAction.class);
|
||||||
|
|
||||||
|
private final TinyRemapperService tinyRemapperService;
|
||||||
private TinyRemapper tinyRemapper;
|
private TinyRemapper tinyRemapper;
|
||||||
|
|
||||||
|
public RemapAction() {
|
||||||
|
this.tinyRemapperService = UnsafeWorkQueueHelper.get(getParameters().getTinyRemapperBuildServiceUuid(), TinyRemapperService.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
try {
|
try {
|
||||||
LOGGER.info("Remapping {} to {}", inputFile, outputFile);
|
LOGGER.info("Remapping {} to {}", inputFile, outputFile);
|
||||||
|
|
||||||
tinyRemapper = createTinyRemapper();
|
tinyRemapper = tinyRemapperService.getTinyRemapperForRemapping();
|
||||||
|
|
||||||
remap();
|
remap();
|
||||||
remapAccessWidener();
|
remapAccessWidener();
|
||||||
|
@ -204,9 +228,6 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||||
modifyJarManifest();
|
modifyJarManifest();
|
||||||
rewriteJar();
|
rewriteJar();
|
||||||
|
|
||||||
tinyRemapper.finish();
|
|
||||||
tinyRemapper = null;
|
|
||||||
|
|
||||||
LOGGER.debug("Finished remapping {}", inputFile);
|
LOGGER.debug("Finished remapping {}", inputFile);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
try {
|
try {
|
||||||
|
@ -220,13 +241,9 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void remap() throws IOException {
|
private void remap() throws IOException {
|
||||||
final InputTag inputTag = tinyRemapper.createInputTag();
|
|
||||||
|
|
||||||
tinyRemapper.readInputsAsync(inputTag, inputFile);
|
|
||||||
|
|
||||||
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(outputFile).build()) {
|
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(outputFile).build()) {
|
||||||
outputConsumer.addNonClassFiles(inputFile);
|
outputConsumer.addNonClassFiles(inputFile);
|
||||||
tinyRemapper.apply(outputConsumer, inputTag);
|
tinyRemapper.apply(outputConsumer, tinyRemapperService.getTag(getParameters().getInputTagName().get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,21 +254,21 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] remapped = remapAccessWidener(accessWidenerFile.content(), tinyRemapper.getEnvironment().getRemapper(), MappingsNamespace.INTERMEDIARY.toString());
|
byte[] remapped = remapAccessWidener(accessWidenerFile.content());
|
||||||
|
|
||||||
// Finally, replace the output with the remaped aw
|
// Finally, replace the output with the remaped aw
|
||||||
ZipUtils.replace(outputFile, accessWidenerFile.path(), remapped);
|
ZipUtils.replace(outputFile, accessWidenerFile.path(), remapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] remapAccessWidener(byte[] input, Remapper asmRemapper, String targetNamespace) {
|
private byte[] remapAccessWidener(byte[] input) {
|
||||||
int version = AccessWidenerReader.readVersion(input);
|
int version = AccessWidenerReader.readVersion(input);
|
||||||
|
|
||||||
AccessWidenerWriter writer = new AccessWidenerWriter(version);
|
AccessWidenerWriter writer = new AccessWidenerWriter(version);
|
||||||
AccessWidenerRemapper remapper = new AccessWidenerRemapper(
|
AccessWidenerRemapper remapper = new AccessWidenerRemapper(
|
||||||
writer,
|
writer,
|
||||||
asmRemapper,
|
tinyRemapper.getEnvironment().getRemapper(),
|
||||||
MappingsNamespace.NAMED.toString(),
|
getParameters().getSourceNamespace().get(),
|
||||||
targetNamespace
|
getParameters().getTargetNamespace().get()
|
||||||
);
|
);
|
||||||
AccessWidenerReader reader = new AccessWidenerReader(remapper);
|
AccessWidenerReader reader = new AccessWidenerReader(remapper);
|
||||||
reader.read(input);
|
reader.read(input);
|
||||||
|
@ -300,30 +317,15 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private TinyRemapper createTinyRemapper() {
|
@Internal
|
||||||
TinyRemapper.Builder builder = TinyRemapper.newRemapper();
|
public TinyRemapperService getTinyRemapperService() {
|
||||||
|
return tinyRemapperService.get();
|
||||||
|
}
|
||||||
|
|
||||||
for (Provider<MappingsService> provider : getParameters().getMappings().get()) {
|
@Internal
|
||||||
builder.withMappings(provider.get().getMappingsProvider());
|
String getInputTagName() {
|
||||||
}
|
return getProject().getPath() + getName();
|
||||||
|
|
||||||
for (File mixinMapping : getParameters().getMixinMappings()) {
|
|
||||||
builder.withMappings(TinyUtils.createTinyMappingProvider(mixinMapping.toPath(), getParameters().getSourceNamespace().get(), getParameters().getTargetNamespace().get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getParameters().getUseMixinExtension().get()) {
|
|
||||||
builder.extension(new net.fabricmc.tinyremapper.extension.mixin.MixinExtension());
|
|
||||||
}
|
|
||||||
|
|
||||||
TinyRemapper remapper = builder.build();
|
|
||||||
|
|
||||||
// Apply classpath
|
|
||||||
for (File file : getParameters().getRemapClasspath()) {
|
|
||||||
remapper.readClassPathAsync(file.toPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
return remapper;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,8 @@ import org.gradle.api.tasks.TaskAction;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import net.fabricmc.loom.task.service.MappingsService;
|
|
||||||
import net.fabricmc.loom.task.service.SourceRemapperService;
|
import net.fabricmc.loom.task.service.SourceRemapperService;
|
||||||
|
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
|
||||||
|
|
||||||
public abstract class RemapSourcesJarTask extends AbstractRemapJarTask {
|
public abstract class RemapSourcesJarTask extends AbstractRemapJarTask {
|
||||||
@Inject
|
@Inject
|
||||||
|
@ -49,12 +49,12 @@ public abstract class RemapSourcesJarTask extends AbstractRemapJarTask {
|
||||||
@TaskAction
|
@TaskAction
|
||||||
public void run() {
|
public void run() {
|
||||||
submitWork(RemapSourcesAction.class, params -> {
|
submitWork(RemapSourcesAction.class, params -> {
|
||||||
params.getSourcesRemapperService().set(SourceRemapperService.create(getProject(), MappingsService.createDefault(getProject(), getSourceNamespace().get(), getTargetNamespace().get()), getClasspath()));
|
params.getSourcesRemapperServiceUuid().set(UnsafeWorkQueueHelper.create(getProject(), SourceRemapperService.create(this)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface RemapSourcesParams extends AbstractRemapParams {
|
public interface RemapSourcesParams extends AbstractRemapParams {
|
||||||
Property<SourceRemapperService> getSourcesRemapperService();
|
Property<String> getSourcesRemapperServiceUuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract static class RemapSourcesAction extends AbstractRemapAction<RemapSourcesParams> {
|
public abstract static class RemapSourcesAction extends AbstractRemapAction<RemapSourcesParams> {
|
||||||
|
@ -65,7 +65,7 @@ public abstract class RemapSourcesJarTask extends AbstractRemapJarTask {
|
||||||
public RemapSourcesAction() {
|
public RemapSourcesAction() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
sourceRemapperService = getParameters().getSourcesRemapperService().get();
|
sourceRemapperService = UnsafeWorkQueueHelper.get(getParameters().getSourcesRemapperServiceUuid(), SourceRemapperService.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -54,8 +54,8 @@ public class RemapTaskConfiguration {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the default remap jar task
|
// Register the default remap jar task - must not be lazy to ensure that the prepare tasks get setup for other projects to depend on.
|
||||||
TaskProvider<RemapJarTask> remapJarTaskProvider = tasks.register(REMAP_JAR_TASK_NAME, RemapJarTask.class, task -> {
|
RemapJarTask remapJarTask = tasks.create(REMAP_JAR_TASK_NAME, RemapJarTask.class, task -> {
|
||||||
final AbstractArchiveTask jarTask = tasks.named(JavaPlugin.JAR_TASK_NAME, AbstractArchiveTask.class).get();
|
final AbstractArchiveTask jarTask = tasks.named(JavaPlugin.JAR_TASK_NAME, AbstractArchiveTask.class).get();
|
||||||
|
|
||||||
// Basic task setup
|
// Basic task setup
|
||||||
|
@ -76,7 +76,7 @@ public class RemapTaskConfiguration {
|
||||||
task.getDestinationDirectory().set(new File(project.getBuildDir(), "devlibs"));
|
task.getDestinationDirectory().set(new File(project.getBuildDir(), "devlibs"));
|
||||||
});
|
});
|
||||||
|
|
||||||
tasks.named(BasePlugin.ASSEMBLE_TASK_NAME).configure(task -> task.dependsOn(remapJarTaskProvider));
|
tasks.named(BasePlugin.ASSEMBLE_TASK_NAME).configure(task -> task.dependsOn(remapJarTask));
|
||||||
|
|
||||||
trySetupSourceRemapping(project);
|
trySetupSourceRemapping(project);
|
||||||
|
|
||||||
|
|
|
@ -24,49 +24,45 @@
|
||||||
|
|
||||||
package net.fabricmc.loom.task.service;
|
package net.fabricmc.loom.task.service;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import org.gradle.api.Project;
|
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.services.BuildService;
|
|
||||||
import org.gradle.api.services.BuildServiceParameters;
|
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||||
|
import net.fabricmc.loom.util.service.SharedService;
|
||||||
|
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||||
import net.fabricmc.mappingio.MappingReader;
|
import net.fabricmc.mappingio.MappingReader;
|
||||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||||
import net.fabricmc.tinyremapper.IMappingProvider;
|
import net.fabricmc.tinyremapper.IMappingProvider;
|
||||||
|
|
||||||
public abstract class MappingsService implements BuildService<MappingsService.Params>, AutoCloseable {
|
public final class MappingsService implements SharedService {
|
||||||
interface Params extends BuildServiceParameters {
|
private record Options(Path mappingsFile, String from, String to, boolean remapLocals) { }
|
||||||
RegularFileProperty getMappingsFile();
|
|
||||||
|
|
||||||
Property<String> getFromNamespace();
|
public static MappingsService create(Project project, String name, Path mappingsFile, String from, String to, boolean remapLocals) {
|
||||||
Property<String> getToNamespace();
|
return create(SharedServiceManager.get(project), name, mappingsFile, from, to, remapLocals);
|
||||||
|
|
||||||
Property<Boolean> getRemapLocals();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static synchronized Provider<MappingsService> create(Project project, String name, File mappingsFile, String from, String to, boolean remapLocals) {
|
public static synchronized MappingsService create(SharedServiceManager sharedServiceManager, String name, Path mappingsFile, String from, String to, boolean remapLocals) {
|
||||||
return project.getGradle().getSharedServices().registerIfAbsent(name, MappingsService.class, spec -> {
|
final Options options = new Options(mappingsFile, from, to, remapLocals);
|
||||||
spec.parameters(params -> {
|
final String id = name + options.hashCode();
|
||||||
params.getMappingsFile().set(mappingsFile);
|
return sharedServiceManager.getOrCreateService(id, () -> new MappingsService(options));
|
||||||
params.getFromNamespace().set(from);
|
|
||||||
params.getToNamespace().set(to);
|
|
||||||
params.getRemapLocals().set(remapLocals);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Provider<MappingsService> createDefault(Project project, String from, String to) {
|
public static MappingsService createDefault(Project project, String from, String to) {
|
||||||
final MappingsProviderImpl mappingsProvider = LoomGradleExtension.get(project).getMappingsProvider();
|
final MappingsProviderImpl mappingsProvider = LoomGradleExtension.get(project).getMappingsProvider();
|
||||||
|
|
||||||
final String name = mappingsProvider.getBuildServiceName("mappingsProvider", from, to);
|
final String name = mappingsProvider.getBuildServiceName("mappingsProvider", from, to);
|
||||||
return MappingsService.create(project, name, mappingsProvider.tinyMappings.toFile(), from, to, false);
|
return MappingsService.create(project, name, mappingsProvider.tinyMappings, from, to, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Options options;
|
||||||
|
|
||||||
|
public MappingsService(Options options) {
|
||||||
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IMappingProvider mappingProvider = null;
|
private IMappingProvider mappingProvider = null;
|
||||||
|
@ -76,13 +72,13 @@ public abstract class MappingsService implements BuildService<MappingsService.Pa
|
||||||
if (mappingProvider == null) {
|
if (mappingProvider == null) {
|
||||||
try {
|
try {
|
||||||
mappingProvider = TinyRemapperHelper.create(
|
mappingProvider = TinyRemapperHelper.create(
|
||||||
getParameters().getMappingsFile().get().getAsFile().toPath(),
|
options.mappingsFile(),
|
||||||
getParameters().getFromNamespace().get(),
|
options.from(),
|
||||||
getParameters().getToNamespace().get(),
|
options.to(),
|
||||||
getParameters().getRemapLocals().get()
|
options.remapLocals()
|
||||||
);
|
);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new UncheckedIOException("Failed to read mappings from: " + getParameters().getMappingsFile().get().getAsFile().getAbsolutePath(), e);
|
throw new UncheckedIOException("Failed to read mappings from: " + options.mappingsFile(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,9 +90,9 @@ public abstract class MappingsService implements BuildService<MappingsService.Pa
|
||||||
memoryMappingTree = new MemoryMappingTree();
|
memoryMappingTree = new MemoryMappingTree();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
MappingReader.read(getParameters().getMappingsFile().get().getAsFile().toPath(), memoryMappingTree);
|
MappingReader.read(options.mappingsFile(), memoryMappingTree);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new UncheckedIOException("Failed to read mappings from: " + getParameters().getMappingsFile().get().getAsFile().getAbsolutePath(), e);
|
throw new UncheckedIOException("Failed to read mappings from: " + options.mappingsFile(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,11 +100,11 @@ public abstract class MappingsService implements BuildService<MappingsService.Pa
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFromNamespace() {
|
public String getFromNamespace() {
|
||||||
return getParameters().getFromNamespace().get();
|
return options.from();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getToNamespace() {
|
public String getToNamespace() {
|
||||||
return getParameters().getToNamespace().get();
|
return options.to();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.task.service;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.tasks.SourceSet;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
|
import net.fabricmc.loom.util.service.SharedService;
|
||||||
|
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||||
|
import net.fabricmc.tinyremapper.IMappingProvider;
|
||||||
|
|
||||||
|
public final class MixinMappingsService implements SharedService {
|
||||||
|
private final SharedServiceManager sharedServiceManager;
|
||||||
|
private final HashSet<File> mixinMappings = new HashSet<>();
|
||||||
|
|
||||||
|
private MixinMappingsService(SharedServiceManager sharedServiceManager) {
|
||||||
|
this.sharedServiceManager = sharedServiceManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File getMixinMappingFile(Project project, SourceSet sourceSet) {
|
||||||
|
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||||
|
File mixinMapping = new File(extension.getFiles().getProjectBuildCache(), "mixin-map-" + extension.getMappingsProvider().mappingsIdentifier() + "." + sourceSet.getName() + ".tiny");
|
||||||
|
|
||||||
|
getService(SharedServiceManager.get(project)).mixinMappings.add(mixinMapping);
|
||||||
|
|
||||||
|
return mixinMapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MixinMappingsService getService(SharedServiceManager sharedServiceManager) {
|
||||||
|
return sharedServiceManager.getOrCreateService("MixinMappings", () -> new MixinMappingsService(sharedServiceManager));
|
||||||
|
}
|
||||||
|
|
||||||
|
IMappingProvider getMappingProvider(String from, String to) {
|
||||||
|
return out -> {
|
||||||
|
for (File mixinMapping : mixinMappings) {
|
||||||
|
if (!mixinMapping.exists()) continue;
|
||||||
|
|
||||||
|
MappingsService service = MappingsService.create(sharedServiceManager, mixinMapping.getAbsolutePath(), mixinMapping.toPath(), from, to, false);
|
||||||
|
service.getMappingsProvider().load(out);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,49 +24,57 @@
|
||||||
|
|
||||||
package net.fabricmc.loom.task.service;
|
package net.fabricmc.loom.task.service;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
import org.cadixdev.lorenz.MappingSet;
|
import org.cadixdev.lorenz.MappingSet;
|
||||||
import org.cadixdev.mercury.Mercury;
|
import org.cadixdev.mercury.Mercury;
|
||||||
import org.cadixdev.mercury.remapper.MercuryRemapper;
|
import org.cadixdev.mercury.remapper.MercuryRemapper;
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
import org.gradle.api.file.ConfigurableFileCollection;
|
import org.gradle.api.file.ConfigurableFileCollection;
|
||||||
import org.gradle.api.file.FileCollection;
|
|
||||||
import org.gradle.api.provider.Property;
|
|
||||||
import org.gradle.api.provider.Provider;
|
|
||||||
import org.gradle.api.services.BuildService;
|
|
||||||
import org.gradle.api.services.BuildServiceParameters;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
|
import net.fabricmc.loom.task.RemapSourcesJarTask;
|
||||||
import net.fabricmc.loom.util.DeletingFileVisitor;
|
import net.fabricmc.loom.util.DeletingFileVisitor;
|
||||||
import net.fabricmc.loom.util.FileSystemUtil;
|
import net.fabricmc.loom.util.FileSystemUtil;
|
||||||
import net.fabricmc.loom.util.SourceRemapper;
|
import net.fabricmc.loom.util.SourceRemapper;
|
||||||
import net.fabricmc.loom.util.ZipUtils;
|
import net.fabricmc.loom.util.ZipUtils;
|
||||||
|
import net.fabricmc.loom.util.service.SharedService;
|
||||||
|
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||||
import net.fabricmc.lorenztiny.TinyMappingsReader;
|
import net.fabricmc.lorenztiny.TinyMappingsReader;
|
||||||
|
|
||||||
public abstract class SourceRemapperService implements BuildService<SourceRemapperService.Params>, AutoCloseable {
|
public final class SourceRemapperService implements SharedService {
|
||||||
public interface Params extends BuildServiceParameters {
|
public static synchronized SourceRemapperService create(RemapSourcesJarTask task) {
|
||||||
Property<Provider<MappingsService>> getMappings();
|
final Project project = task.getProject();
|
||||||
|
final String to = task.getTargetNamespace().get();
|
||||||
|
final String from = task.getSourceNamespace().get();
|
||||||
|
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||||
|
final SharedServiceManager sharedServiceManager = SharedServiceManager.get(project);
|
||||||
|
final String id = extension.getMappingsProvider().getBuildServiceName("sourceremapper", from, to);
|
||||||
|
|
||||||
ConfigurableFileCollection getClasspath();
|
return sharedServiceManager.getOrCreateService(id, () ->
|
||||||
}
|
new SourceRemapperService(MappingsService.createDefault(project, from, to), task.getClasspath()
|
||||||
|
));
|
||||||
public static synchronized Provider<SourceRemapperService> create(Project project, Provider<MappingsService> mappings, FileCollection classpath) {
|
|
||||||
// TODO may need a better name, im not too sure
|
|
||||||
return project.getGradle().getSharedServices().registerIfAbsent("sourceremapper", SourceRemapperService.class, spec ->
|
|
||||||
spec.parameters(params -> {
|
|
||||||
params.getMappings().set(mappings);
|
|
||||||
params.getClasspath().from(classpath);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(SourceRemapperService.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(SourceRemapperService.class);
|
||||||
|
|
||||||
private Mercury mercury;
|
private final MappingsService mappingsService;
|
||||||
|
private final ConfigurableFileCollection classpath;
|
||||||
|
|
||||||
|
private final Supplier<Mercury> mercury = Suppliers.memoize(this::createMercury);
|
||||||
|
|
||||||
|
private SourceRemapperService(MappingsService mappingsService, ConfigurableFileCollection classpath) {
|
||||||
|
this.mappingsService = mappingsService;
|
||||||
|
this.classpath = classpath;
|
||||||
|
}
|
||||||
|
|
||||||
public void remapSourcesJar(Path source, Path destination) throws IOException {
|
public void remapSourcesJar(Path source, Path destination) throws IOException {
|
||||||
if (source.equals(destination)) {
|
if (source.equals(destination)) {
|
||||||
|
@ -99,35 +107,34 @@ public abstract class SourceRemapperService implements BuildService<SourceRemapp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void doRemap(Path srcPath, Path dstPath, Path source) throws IOException {
|
private synchronized void doRemap(Path srcPath, Path dstPath, Path source) {
|
||||||
if (mercury == null) {
|
|
||||||
mercury = new Mercury();
|
|
||||||
mercury.setGracefulClasspathChecks(true);
|
|
||||||
mercury.getProcessors().add(MercuryRemapper.create(getMappings()));
|
|
||||||
|
|
||||||
getParameters().getClasspath().forEach(file -> mercury.getClassPath().add(file.toPath()));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Not thread safe!!
|
synchronized (mercury) {
|
||||||
mercury.rewrite(srcPath, dstPath);
|
mercury.get().rewrite(srcPath, dstPath);
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.warn("Could not remap " + source + " fully!", e);
|
LOGGER.warn("Could not remap " + source + " fully!", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MappingSet getMappings() throws IOException {
|
private MappingSet getMappings() throws IOException {
|
||||||
return new TinyMappingsReader(mappingsService().getMemoryMappingTree(), mappingsService().getFromNamespace(), mappingsService().getToNamespace()).read();
|
return new TinyMappingsReader(mappingsService.getMemoryMappingTree(), mappingsService.getFromNamespace(), mappingsService.getToNamespace()).read();
|
||||||
}
|
}
|
||||||
|
|
||||||
private MappingsService mappingsService() {
|
private Mercury createMercury() {
|
||||||
return getParameters().getMappings().get().get();
|
var mercury = new Mercury();
|
||||||
}
|
mercury.setGracefulClasspathChecks(true);
|
||||||
|
|
||||||
@Override
|
try {
|
||||||
public void close() throws Exception {
|
mercury.getProcessors().add(MercuryRemapper.create(getMappings()));
|
||||||
mercury = null;
|
} catch (IOException e) {
|
||||||
// This is required (:
|
throw new UncheckedIOException("Failed to read mercury mappings", e);
|
||||||
System.gc();
|
}
|
||||||
|
|
||||||
|
for (File file : classpath.getFiles()) {
|
||||||
|
mercury.getClassPath().add(file.toPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
return mercury;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.task.service;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
|
import net.fabricmc.loom.task.AbstractRemapJarTask;
|
||||||
|
import net.fabricmc.loom.util.service.SharedService;
|
||||||
|
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||||
|
import net.fabricmc.tinyremapper.IMappingProvider;
|
||||||
|
import net.fabricmc.tinyremapper.InputTag;
|
||||||
|
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||||
|
|
||||||
|
public class TinyRemapperService implements SharedService {
|
||||||
|
public static synchronized TinyRemapperService getOrCreate(AbstractRemapJarTask remapJarTask) {
|
||||||
|
final Project project = remapJarTask.getProject();
|
||||||
|
final String to = remapJarTask.getTargetNamespace().get();
|
||||||
|
final String from = remapJarTask.getSourceNamespace().get();
|
||||||
|
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||||
|
final SharedServiceManager sharedServiceManager = SharedServiceManager.get(project);
|
||||||
|
final boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get();
|
||||||
|
|
||||||
|
// 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 String id = extension.getMappingsProvider().getBuildServiceName("remapJarService", from, to) + ":" + remapJarTask.getName();
|
||||||
|
|
||||||
|
TinyRemapperService service = sharedServiceManager.getOrCreateService(id, () -> {
|
||||||
|
List<IMappingProvider> mappings = new ArrayList<>();
|
||||||
|
mappings.add(MappingsService.createDefault(project, from, to).getMappingsProvider());
|
||||||
|
|
||||||
|
if (legacyMixin) {
|
||||||
|
mappings.add(MixinMappingsService.getService(SharedServiceManager.get(project)).getMappingProvider(from, to));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TinyRemapperService(mappings, !legacyMixin);
|
||||||
|
});
|
||||||
|
|
||||||
|
service.readClasspath(remapJarTask.getClasspath().getFiles().stream().map(File::toPath).toList());
|
||||||
|
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TinyRemapper tinyRemapper;
|
||||||
|
private final Map<String, InputTag> inputTagMap = new ConcurrentHashMap<>();
|
||||||
|
private final HashSet<Path> classpath = new HashSet<>();
|
||||||
|
// Set to true once remapping has started, once set no inputs can be read.
|
||||||
|
private boolean isRemapping = false;
|
||||||
|
|
||||||
|
public TinyRemapperService(List<IMappingProvider> mappings, boolean useMixinExtension) {
|
||||||
|
TinyRemapper.Builder builder = TinyRemapper.newRemapper();
|
||||||
|
|
||||||
|
for (IMappingProvider provider : mappings) {
|
||||||
|
builder.withMappings(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useMixinExtension) {
|
||||||
|
builder.extension(new net.fabricmc.tinyremapper.extension.mixin.MixinExtension());
|
||||||
|
}
|
||||||
|
|
||||||
|
tinyRemapper = builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputTag createTag(String key) {
|
||||||
|
if (inputTagMap.containsKey(key)) {
|
||||||
|
throw new IllegalStateException("Input tag already exists for key: " + key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputTagMap.put(key, tinyRemapper.createInputTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputTag getTag(String key) {
|
||||||
|
return Objects.requireNonNull(inputTagMap.get(key), "Input tag not found for: " + key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TinyRemapper getTinyRemapperForRemapping() {
|
||||||
|
synchronized (this) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void readClasspath(List<Path> paths) {
|
||||||
|
List<Path> toRead;
|
||||||
|
|
||||||
|
synchronized (classpath) {
|
||||||
|
toRead = paths.stream().filter(path -> !classpath.contains(path)).toList();
|
||||||
|
classpath.addAll(paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
tinyRemapper.readClassPathAsync(toRead.toArray(Path[]::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (tinyRemapper != null) {
|
||||||
|
tinyRemapper.finish();
|
||||||
|
tinyRemapper = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ import java.util.zip.GZIPInputStream;
|
||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
import org.gradle.api.logging.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradlePlugin;
|
import net.fabricmc.loom.LoomGradlePlugin;
|
||||||
|
|
||||||
|
|
|
@ -110,21 +110,31 @@ public final class TinyRemapperHelper {
|
||||||
|
|
||||||
public static IMappingProvider create(MappingTree mappings, String from, String to, boolean remapLocalVariables) {
|
public static IMappingProvider create(MappingTree mappings, String from, String to, boolean remapLocalVariables) {
|
||||||
return (acceptor) -> {
|
return (acceptor) -> {
|
||||||
|
final int fromId = mappings.getNamespaceId(from);
|
||||||
|
final int toId = mappings.getNamespaceId(to);
|
||||||
|
|
||||||
for (MappingTree.ClassMapping classDef : mappings.getClasses()) {
|
for (MappingTree.ClassMapping classDef : mappings.getClasses()) {
|
||||||
String className = classDef.getName(from);
|
String className = classDef.getName(fromId);
|
||||||
acceptor.acceptClass(className, classDef.getName(to));
|
String dstName = classDef.getName(toId);
|
||||||
|
|
||||||
|
if (dstName == null) {
|
||||||
|
// Unsure if this is correct, should be better than crashing tho.
|
||||||
|
dstName = className;
|
||||||
|
}
|
||||||
|
|
||||||
|
acceptor.acceptClass(className, dstName);
|
||||||
|
|
||||||
for (MappingTree.FieldMapping field : classDef.getFields()) {
|
for (MappingTree.FieldMapping field : classDef.getFields()) {
|
||||||
acceptor.acceptField(memberOf(className, field.getName(from), field.getDesc(from)), field.getName(to));
|
acceptor.acceptField(memberOf(className, field.getName(fromId), field.getDesc(fromId)), field.getName(toId));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (MappingTree.MethodMapping method : classDef.getMethods()) {
|
for (MappingTree.MethodMapping method : classDef.getMethods()) {
|
||||||
IMappingProvider.Member methodIdentifier = memberOf(className, method.getName(from), method.getDesc(from));
|
IMappingProvider.Member methodIdentifier = memberOf(className, method.getName(fromId), method.getDesc(fromId));
|
||||||
acceptor.acceptMethod(methodIdentifier, method.getName(to));
|
acceptor.acceptMethod(methodIdentifier, method.getName(toId));
|
||||||
|
|
||||||
if (remapLocalVariables) {
|
if (remapLocalVariables) {
|
||||||
for (MappingTree.MethodArgMapping parameter : method.getArgs()) {
|
for (MappingTree.MethodArgMapping parameter : method.getArgs()) {
|
||||||
String name = parameter.getName(to);
|
String name = parameter.getName(toId);
|
||||||
|
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -136,7 +146,7 @@ public final class TinyRemapperHelper {
|
||||||
for (MappingTree.MethodVarMapping localVariable : method.getVars()) {
|
for (MappingTree.MethodVarMapping localVariable : method.getVars()) {
|
||||||
acceptor.acceptMethodVar(methodIdentifier, localVariable.getLvIndex(),
|
acceptor.acceptMethodVar(methodIdentifier, localVariable.getLvIndex(),
|
||||||
localVariable.getStartOpIdx(), localVariable.getLvtRowIndex(),
|
localVariable.getStartOpIdx(), localVariable.getLvtRowIndex(),
|
||||||
localVariable.getName(to));
|
localVariable.getName(toId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* 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.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.gradle.BuildResult;
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.invocation.Gradle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple manager for {@link SharedService} to be used across gradle (sub) projects.
|
||||||
|
* This is a basic replacement for gradle's build service api.
|
||||||
|
*/
|
||||||
|
public final class SharedServiceManager {
|
||||||
|
private static final Map<Gradle, SharedServiceManager> SERVICE_FACTORY_MAP = new ConcurrentHashMap<>();
|
||||||
|
private final Gradle gradle;
|
||||||
|
|
||||||
|
private final Map<String, SharedService> sharedServiceMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private boolean shutdown = false;
|
||||||
|
|
||||||
|
private SharedServiceManager(Gradle gradle) {
|
||||||
|
this.gradle = gradle;
|
||||||
|
this.gradle.buildFinished(this::onFinish);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SharedServiceManager get(Project project) {
|
||||||
|
return get(project.getGradle());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SharedServiceManager get(Gradle gradle) {
|
||||||
|
return SERVICE_FACTORY_MAP.computeIfAbsent(gradle, SharedServiceManager::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
sharedService = function.get();
|
||||||
|
sharedServiceMap.put(id, sharedService);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sharedService;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onFinish(BuildResult buildResult) {
|
||||||
|
synchronized (sharedServiceMap) {
|
||||||
|
shutdown = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SERVICE_FACTORY_MAP.remove(gradle);
|
||||||
|
|
||||||
|
final List<IOException> exceptionList = new ArrayList<>();
|
||||||
|
|
||||||
|
for (SharedService sharedService : sharedServiceMap.values()) {
|
||||||
|
try {
|
||||||
|
sharedService.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
exceptionList.add(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sharedServiceMap.clear();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is required to ensure that mercury releases all of the file handles.
|
||||||
|
System.gc();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* 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.Project;
|
||||||
|
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(Project project, SharedService service) {
|
||||||
|
final String uuid = UUID.randomUUID().toString();
|
||||||
|
SERVICE_MAP.put(uuid, service);
|
||||||
|
|
||||||
|
// Ensure we don't make a mess if things go wrong.
|
||||||
|
project.getGradle().buildFinished(buildResult -> SERVICE_MAP.remove(uuid));
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ import org.gradle.util.GradleVersion
|
||||||
|
|
||||||
class LoomTestConstants {
|
class LoomTestConstants {
|
||||||
public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion()
|
public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion()
|
||||||
public final static String PRE_RELEASE_GRADLE = "7.5-20220101231120+0000"
|
public final static String PRE_RELEASE_GRADLE = "7.5-20220110230252+0000"
|
||||||
|
|
||||||
public final static String[] STANDARD_TEST_VERSIONS = [DEFAULT_GRADLE, PRE_RELEASE_GRADLE]
|
public final static String[] STANDARD_TEST_VERSIONS = [DEFAULT_GRADLE, PRE_RELEASE_GRADLE]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* 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.test.benchmark
|
||||||
|
|
||||||
|
import groovy.time.TimeCategory
|
||||||
|
import groovy.time.TimeDuration
|
||||||
|
import net.fabricmc.loom.test.LoomTestConstants
|
||||||
|
import net.fabricmc.loom.test.util.GradleProjectTestTrait
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run this class, passing a working dir as the first argument.
|
||||||
|
* Allow for one warm up run before profiling, follow up runs should not be using the network.
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
class FabricAPIBenchmark implements GradleProjectTestTrait {
|
||||||
|
def run(File dir) {
|
||||||
|
def gradle = gradleProject(
|
||||||
|
version: LoomTestConstants.PRE_RELEASE_GRADLE,
|
||||||
|
projectDir: new File(dir, "project"),
|
||||||
|
gradleHomeDir: new File(dir, "gradlehome"),
|
||||||
|
allowExistingRepo: true,
|
||||||
|
|
||||||
|
repo: "https://github.com/FabricMC/fabric.git",
|
||||||
|
commit: "71b634e5b7845296b11be3fa6545f4fbfacc017f",
|
||||||
|
patch: "fabric_api"
|
||||||
|
)
|
||||||
|
|
||||||
|
def timeStart = new Date()
|
||||||
|
|
||||||
|
def result = gradle.run(tasks: ["clean", "build"], args: ["--parallel", "-x", "check", "-x", "test", "-x", ":fabric-data-generation-api-v1:runDatagen", "-x", "javadoc"])
|
||||||
|
|
||||||
|
def timeStop = new Date()
|
||||||
|
TimeDuration duration = TimeCategory.minus(timeStop, timeStart)
|
||||||
|
println(duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
static void main(String[] args) {
|
||||||
|
getInstance().run(new File(args[0]))
|
||||||
|
System.exit(0)
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,7 +29,7 @@ import net.fabricmc.loom.configuration.providers.mappings.intermediary.Intermedi
|
||||||
class IntermediaryMappingLayerTest extends LayeredMappingsSpecification {
|
class IntermediaryMappingLayerTest extends LayeredMappingsSpecification {
|
||||||
def "Read intermediary mappings" () {
|
def "Read intermediary mappings" () {
|
||||||
setup:
|
setup:
|
||||||
mockMappingsProvider.intermediaryTinyFile() >> extractFileFromZip(downloadFile(INTERMEDIARY_1_17_URL, "intermediary.jar"), "mappings/mappings.tiny")
|
intermediaryUrl = INTERMEDIARY_1_17_URL
|
||||||
when:
|
when:
|
||||||
def mappings = getSingleMapping(new IntermediaryMappingsSpec())
|
def mappings = getSingleMapping(new IntermediaryMappingsSpec())
|
||||||
def tiny = getTiny(mappings)
|
def tiny = getTiny(mappings)
|
||||||
|
|
|
@ -24,15 +24,14 @@
|
||||||
|
|
||||||
package net.fabricmc.loom.test.unit.layeredmappings
|
package net.fabricmc.loom.test.unit.layeredmappings
|
||||||
|
|
||||||
import groovy.transform.CompileStatic
|
|
||||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider
|
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec
|
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsProcessor
|
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingContext
|
import net.fabricmc.loom.api.mappings.layered.MappingContext
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingLayer
|
import net.fabricmc.loom.api.mappings.layered.MappingLayer
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace
|
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider
|
|
||||||
import net.fabricmc.loom.api.mappings.layered.spec.MappingsSpec
|
import net.fabricmc.loom.api.mappings.layered.spec.MappingsSpec
|
||||||
|
import net.fabricmc.loom.configuration.providers.mappings.IntermediaryService
|
||||||
|
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec
|
||||||
|
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsProcessor
|
||||||
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider
|
||||||
import net.fabricmc.mappingio.adapter.MappingDstNsReorder
|
import net.fabricmc.mappingio.adapter.MappingDstNsReorder
|
||||||
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch
|
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch
|
||||||
import net.fabricmc.mappingio.format.Tiny2Writer
|
import net.fabricmc.mappingio.format.Tiny2Writer
|
||||||
|
@ -42,13 +41,13 @@ import org.gradle.api.logging.Logger
|
||||||
import spock.lang.Specification
|
import spock.lang.Specification
|
||||||
|
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
import java.util.function.Supplier
|
||||||
import java.util.zip.ZipFile
|
import java.util.zip.ZipFile
|
||||||
|
|
||||||
abstract class LayeredMappingsSpecification extends Specification implements LayeredMappingsTestConstants {
|
abstract class LayeredMappingsSpecification extends Specification implements LayeredMappingsTestConstants {
|
||||||
Logger mockLogger = Mock(Logger)
|
Logger mockLogger = Mock(Logger)
|
||||||
MappingsProvider mockMappingsProvider = Mock(MappingsProvider)
|
|
||||||
MinecraftProvider mockMinecraftProvider = Mock(MinecraftProvider)
|
MinecraftProvider mockMinecraftProvider = Mock(MinecraftProvider)
|
||||||
|
String intermediaryUrl
|
||||||
MappingContext mappingContext = new TestMappingContext()
|
MappingContext mappingContext = new TestMappingContext()
|
||||||
|
|
||||||
File tempDir = File.createTempDir()
|
File tempDir = File.createTempDir()
|
||||||
|
@ -102,7 +101,12 @@ abstract class LayeredMappingsSpecification extends Specification implements Lay
|
||||||
return reorderedMappings
|
return reorderedMappings
|
||||||
}
|
}
|
||||||
|
|
||||||
@CompileStatic
|
def setup() {
|
||||||
|
mockMinecraftProvider.file(_) >> { args ->
|
||||||
|
return new File(tempDir, args[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class TestMappingContext implements MappingContext {
|
class TestMappingContext implements MappingContext {
|
||||||
@Override
|
@Override
|
||||||
Path resolveDependency(Dependency dependency) {
|
Path resolveDependency(Dependency dependency) {
|
||||||
|
@ -116,8 +120,10 @@ abstract class LayeredMappingsSpecification extends Specification implements Lay
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
MappingsProvider mappingsProvider() {
|
Supplier<MemoryMappingTree> intermediaryTree() {
|
||||||
return mockMappingsProvider
|
return {
|
||||||
|
IntermediaryService.create(intermediaryUrl, minecraftProvider()).memoryMappingTree
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -30,7 +30,7 @@ import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsS
|
||||||
class MojangMappingLayerTest extends LayeredMappingsSpecification {
|
class MojangMappingLayerTest extends LayeredMappingsSpecification {
|
||||||
def "Read mojang mappings with synthetic field names" () {
|
def "Read mojang mappings with synthetic field names" () {
|
||||||
setup:
|
setup:
|
||||||
mockMappingsProvider.intermediaryTinyFile() >> extractFileFromZip(downloadFile(INTERMEDIARY_1_17_URL, "intermediary.jar"), "mappings/mappings.tiny")
|
intermediaryUrl = INTERMEDIARY_1_17_URL
|
||||||
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_17
|
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_17
|
||||||
when:
|
when:
|
||||||
def mappings = getLayeredMappings(
|
def mappings = getLayeredMappings(
|
||||||
|
@ -50,7 +50,7 @@ class MojangMappingLayerTest extends LayeredMappingsSpecification {
|
||||||
|
|
||||||
def "Read mojang mappings without synthetic field names" () {
|
def "Read mojang mappings without synthetic field names" () {
|
||||||
setup:
|
setup:
|
||||||
mockMappingsProvider.intermediaryTinyFile() >> extractFileFromZip(downloadFile(INTERMEDIARY_1_17_URL, "intermediary.jar"), "mappings/mappings.tiny")
|
intermediaryUrl = INTERMEDIARY_1_17_URL
|
||||||
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_17
|
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_17
|
||||||
when:
|
when:
|
||||||
def mappings = getLayeredMappings(
|
def mappings = getLayeredMappings(
|
||||||
|
|
|
@ -32,7 +32,7 @@ import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMap
|
||||||
class ParchmentMappingLayerTest extends LayeredMappingsSpecification {
|
class ParchmentMappingLayerTest extends LayeredMappingsSpecification {
|
||||||
def "Read parchment mappings" () {
|
def "Read parchment mappings" () {
|
||||||
setup:
|
setup:
|
||||||
mockMappingsProvider.intermediaryTinyFile() >> extractFileFromZip(downloadFile(INTERMEDIARY_1_16_5_URL, "intermediary.jar"), "mappings/mappings.tiny")
|
intermediaryUrl = INTERMEDIARY_1_16_5_URL
|
||||||
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_16_5
|
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_16_5
|
||||||
when:
|
when:
|
||||||
withMavenFile(PARCHMENT_NOTATION, downloadFile(PARCHMENT_URL, "parchment.zip"))
|
withMavenFile(PARCHMENT_NOTATION, downloadFile(PARCHMENT_URL, "parchment.zip"))
|
||||||
|
@ -55,7 +55,7 @@ class ParchmentMappingLayerTest extends LayeredMappingsSpecification {
|
||||||
|
|
||||||
def "Read parchment mappings remove prefix" () {
|
def "Read parchment mappings remove prefix" () {
|
||||||
setup:
|
setup:
|
||||||
mockMappingsProvider.intermediaryTinyFile() >> extractFileFromZip(downloadFile(INTERMEDIARY_1_16_5_URL, "intermediary.jar"), "mappings/mappings.tiny")
|
intermediaryUrl = INTERMEDIARY_1_16_5_URL
|
||||||
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_16_5
|
mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_16_5
|
||||||
when:
|
when:
|
||||||
withMavenFile(PARCHMENT_NOTATION, downloadFile(PARCHMENT_URL, "parchment.zip"))
|
withMavenFile(PARCHMENT_NOTATION, downloadFile(PARCHMENT_URL, "parchment.zip"))
|
||||||
|
|
|
@ -65,6 +65,10 @@ trait GradleProjectTestTrait {
|
||||||
String repo = options.repo
|
String repo = options.repo
|
||||||
String commit = options.commit
|
String commit = options.commit
|
||||||
|
|
||||||
|
if (options.allowExistingRepo && projectDir.listFiles()?.length > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
exec(projectDir, "git", "clone", repo, ".")
|
exec(projectDir, "git", "clone", repo, ".")
|
||||||
exec(projectDir, "git", "checkout", commit)
|
exec(projectDir, "git", "checkout", commit)
|
||||||
|
|
||||||
|
@ -85,6 +89,7 @@ trait GradleProjectTestTrait {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void exec(File projectDir, String... args) {
|
private void exec(File projectDir, String... args) {
|
||||||
|
projectDir.mkdirs()
|
||||||
def process = args.execute([], projectDir)
|
def process = args.execute([], projectDir)
|
||||||
process.consumeProcessOutput(System.out, System.err)
|
process.consumeProcessOutput(System.out, System.err)
|
||||||
|
|
||||||
|
|
|
@ -90,9 +90,8 @@ shadowJar {
|
||||||
}
|
}
|
||||||
|
|
||||||
remapJar {
|
remapJar {
|
||||||
dependsOn(shadowJar)
|
|
||||||
archiveClassifier.set("universal")
|
archiveClassifier.set("universal")
|
||||||
input.fileValue(tasks["shadowJar"].outputs.files.singleFile)
|
inputFile = shadowJar.archiveFile
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
|
Loading…
Reference in New Issue