Better Mixin AP configuration (#423)

* [SPON-15] Apply Mixin AP config for all projects.

* Revert "[SPON-15] Apply Mixin AP config for all projects."

This reverts commit 93576e83b1221949d551b6307938f7dd6dc8fbbe.

* use setter & getter

* fix broken test introduced in 54d6ef7896

* initial commit for mixin extension

* refactor getConfiguration

* apply mixin extension

* [SPON-15] allow across project AP config

* [SPON-15] revert some changes

* [SPON-15] refactor codes

* [SPON-15] fix bugs

* [SPON-15] bring back cross-project apconfig

* [SPON-15] bug fix: move add default sourceSet earlier

* [SPON-15] fix style

* [SPON-15] refactor MixinAPExtension

* add test

* update test

* [SPON-15] fix test

* Update MixinAnnotationProcessorExtension.java

* [SPON-15] fix test

* fix deprecated gradle API

* [SPON-15] refactor ApInvoker

* [SPON-15] refactor ApInvoker

* allow change refmap name in sourceSet bases

* add new condition on test

* [SPON-15] fix wrong suffix

* Revert "[SPON-15] fix wrong suffix"

This reverts commit 98910392d91c26cd0454cca8cfc03c4e3d417fd6.

* fix mixinjson suffix

* use stream instead of collection for mixin json name

* change name for function

* use correct auto-refmap

* fix file name

* add with action

* add test

* refactor some codes

* refactor code

* update test

* fix checkstyle

* better error message

* fix checkstyle

* remove corss project option

* allow mixin inside loom

* remove project0

I should remove all project0. If I forget one please tell me.

* move `mixin` inside `loom`

* fix spotless

* merge attempt

* fix checkstyle

* seperate api & impl

* add experimental annotation for API

* use API

* Fix indentation

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* fix typo

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* fix typo

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* better javadoc

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>
This commit is contained in:
LogicFan
2021-07-18 09:13:47 -04:00
committed by GitHub
parent b4ac68825f
commit 81fa551382
43 changed files with 1342 additions and 104 deletions

View File

@@ -44,6 +44,7 @@ import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider;
import net.fabricmc.loom.extension.LoomFiles;
import net.fabricmc.loom.extension.LoomGradleExtensionImpl;
import net.fabricmc.loom.extension.MixinApExtension;
public interface LoomGradleExtension extends LoomGradleExtensionAPI {
static LoomGradleExtension get(Project project) {
@@ -102,4 +103,6 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI {
// TODO reimplement a way to change this, was never really supported api anyway
return String.format("https://maven.fabricmc.net/net/fabricmc/intermediary/%1$s/intermediary-%1$s-v2.jar", minecraftVersion);
}
MixinApExtension getMixinApExtension();
}

View File

@@ -31,6 +31,7 @@ import org.gradle.api.Action;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.file.ConfigurableFileCollection;
import org.jetbrains.annotations.ApiStatus;
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
@@ -81,6 +82,9 @@ public interface LoomGradleExtensionAPI {
NamedDomainObjectContainer<RunConfigSettings> getRunConfigs();
@ApiStatus.Experimental
void mixin(Action<MixinApExtensionAPI> action);
void setCustomManifest(String customManifest);
String getCustomManifest();

View File

@@ -0,0 +1,92 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.api;
import org.gradle.api.Action;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.util.PatternSet;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Experimental
public interface MixinApExtensionAPI {
/**
* Apply Mixin AP to sourceSet.
* @param sourceSet the sourceSet that applies Mixin AP.
* @param refmapName the output ref-map name. By default this will
* be {@link net.fabricmc.loom.LoomGradleExtension#getRefmapName()}
* @param action used for filter the mixin json files. By default this will be all files
* with name {@code *.mixins.json} that is inside the {@code resources} folder
* of {@code sourceSet}.
*/
void add(SourceSet sourceSet, String refmapName, Action<PatternSet> action);
/**
* Apply Mixin AP to sourceSet. See {@link MixinApExtensionAPI#add(SourceSet, String, Action)} for more detail.
* @param sourceSet the sourceSet that applies Mixin AP.
* @param refmapName the output ref-map name.
*/
void add(SourceSet sourceSet, String refmapName);
/**
* Apply Mixin AP to sourceSet. See {@link MixinApExtensionAPI#add(SourceSet, String, Action)} for more detail.
* @param sourceSet the sourceSet that applies Mixin AP.
* @param action used for filter the mixin json files.
*/
void add(SourceSet sourceSet, Action<PatternSet> action);
/**
* Apply Mixin AP to sourceSet. See {@link MixinApExtensionAPI#add(SourceSet, String, Action)} for more detail.
* @param sourceSet the sourceSet that applies Mixin AP.
*/
void add(SourceSet sourceSet);
/**
* Apply Mixin AP to sourceSet. See {@link MixinApExtensionAPI#add(SourceSet, String, Action)} for more detail.
* @param sourceSetName the name of sourceSet that applies Mixin AP.
* @param refmapName the output ref-map name.
* @param action used for filter the mixin json files.
*/
void add(String sourceSetName, String refmapName, Action<PatternSet> action);
/**
* Apply Mixin AP to sourceSet. See {@link MixinApExtensionAPI#add(SourceSet, String, Action)} for more detail.
* @param sourceSetName the name of sourceSet that applies Mixin AP.
* @param refmapName the output ref-map name.
*/
void add(String sourceSetName, String refmapName);
/**
* Apply Mixin AP to sourceSet. See {@link MixinApExtensionAPI#add(SourceSet, String, Action)} for more detail.
* @param sourceSetName the name of sourceSet that applies Mixin AP.
* @param action used for filter the mixin json files.
*/
void add(String sourceSetName, Action<PatternSet> action);
/**
* Apply Mixin AP to sourceSet. See {@link MixinApExtensionAPI#add(SourceSet, String, Action)} for more detail.
* @param sourceSetName the name of sourceSet that applies Mixin AP.
*/
void add(String sourceSetName);
}

View File

@@ -25,71 +25,47 @@
package net.fabricmc.loom.build;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.Set;
import java.util.Objects;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import com.google.gson.JsonObject;
import org.gradle.api.Project;
import org.zeroturnaround.zip.ZipUtil;
import org.zeroturnaround.zip.transform.StringZipEntryTransformer;
import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.LoomGradlePlugin;
import net.fabricmc.loom.extension.MixinApExtension;
public final class MixinRefmapHelper {
private MixinRefmapHelper() { }
public static boolean addRefmapName(String filename, Path outputPath) {
public static boolean addRefmapName(Project project, Path outputPath) {
MixinApExtension mixin = LoomGradleExtension.get(project).getMixinApExtension();
File output = outputPath.toFile();
Set<String> mixinFilenames = findMixins(output, true);
if (mixinFilenames.size() > 0) {
return ZipUtil.transformEntries(output, mixinFilenames.stream().map((f) -> new ZipEntryTransformerEntry(f, new StringZipEntryTransformer("UTF-8") {
return mixin.getMixinSourceSetsStream().map(sourceSet -> {
MixinApExtension.MixinInformationContainer container = Objects.requireNonNull(
MixinApExtension.getMixinInformationContainer(sourceSet)
);
Stream<String> mixinJsonNames = container.getMixinJsonNames();
String refmapName = container.getRefmapName();
return ZipUtil.transformEntries(output, mixinJsonNames.map(f -> new ZipEntryTransformerEntry(f, new StringZipEntryTransformer("UTF-8") {
@Override
protected String transform(ZipEntry zipEntry, String input) throws IOException {
protected String transform(ZipEntry zipEntry, String input) {
JsonObject json = LoomGradlePlugin.GSON.fromJson(input, JsonObject.class);
if (!json.has("refmap")) {
json.addProperty("refmap", filename);
json.addProperty("refmap", refmapName);
}
return LoomGradlePlugin.GSON.toJson(json);
}
})).toArray(ZipEntryTransformerEntry[]::new));
} else {
return false;
}
}
private static Set<String> findMixins(File output, boolean onlyWithoutRefmap) {
// first, identify all of the mixin files
Set<String> mixinFilename = new HashSet<>();
// TODO: this is a lovely hack
ZipUtil.iterate(output, (stream, entry) -> {
if (!entry.isDirectory() && entry.getName().endsWith(".json") && !entry.getName().contains("/") && !entry.getName().contains("\\")) {
// JSON file in root directory
try (InputStreamReader inputStreamReader = new InputStreamReader(stream)) {
JsonObject json = LoomGradlePlugin.GSON.fromJson(inputStreamReader, JsonObject.class);
if (json != null) {
boolean hasMixins = json.has("mixins") && json.get("mixins").isJsonArray();
boolean hasClient = json.has("client") && json.get("client").isJsonArray();
boolean hasServer = json.has("server") && json.get("server").isJsonArray();
if (json.has("package") && (hasMixins || hasClient || hasServer)) {
if (!onlyWithoutRefmap || !json.has("refmap") || !json.has("minVersion")) {
mixinFilename.add(entry.getName());
}
}
}
} catch (Exception ignored) {
// ...
}
}
});
return mixinFilename;
}).reduce(false, Boolean::logicalOr);
}
}

View File

@@ -29,16 +29,17 @@ import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskCollection;
import net.fabricmc.loom.extension.MixinApExtension;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.util.Constants;
@@ -48,37 +49,46 @@ import net.fabricmc.loom.util.Constants;
* See Java and Kapt implementations for a more deep understanding of the things passed by the children.
*/
public abstract class AnnotationProcessorInvoker<T extends Task> {
public static final String JAVA = "java";
public static final String SCALA = "scala";
protected final Project project;
private final Collection<Configuration> annotationProcessorConfigurations;
protected final TaskCollection<T> invokerTasks;
protected final Map<SourceSet, T> invokerTasks;
private final Collection<Configuration> apConfigurations;
protected AnnotationProcessorInvoker(Project project,
Collection<Configuration> annotationProcessorConfigurations,
TaskCollection<T> invokerTasks) {
Collection<Configuration> apConfigurations,
Map<SourceSet, T> invokerTasks) {
this.project = project;
this.annotationProcessorConfigurations = annotationProcessorConfigurations;
this.apConfigurations = apConfigurations;
this.invokerTasks = invokerTasks;
}
protected static Collection<Configuration> getApConfigurations(Project project, Function<String, String> getApConfigNameFunc) {
MixinApExtension mixin = LoomGradleExtension.get(project).getMixinApExtension();
return mixin.getApConfigurationsStream(getApConfigNameFunc).collect(Collectors.toList());
}
protected abstract void passArgument(T compileTask, String key, String value);
protected abstract File getDestinationDir(T task);
protected abstract File getRefmapDestinationDir(T task);
protected final String getRefmapDestination(T task, LoomGradleExtension extension) throws IOException {
return new File(getDestinationDir(task), extension.getRefmapName()).getCanonicalPath();
protected final String getRefmapDestination(T task, String refmapName) throws IOException {
return new File(getRefmapDestinationDir(task), refmapName).getCanonicalPath();
}
private void passMixinArguments(T task) {
private void passMixinArguments(T task, SourceSet sourceSet) {
try {
LoomGradleExtension extension = LoomGradleExtension.get(project);
LoomGradleExtension loom = LoomGradleExtension.get(project);
String refmapName = Objects.requireNonNull(MixinApExtension.getMixinInformationContainer(sourceSet)).getRefmapName();
Map<String, String> args = new HashMap<>() {{
put(Constants.MixinArguments.IN_MAP_FILE_NAMED_INTERMEDIARY, extension.getMappingsProvider().tinyMappings.getCanonicalPath());
put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, extension.getNextMixinMappings().getCanonicalPath());
put(Constants.MixinArguments.OUT_REFMAP_FILE, getRefmapDestination(task, extension));
put(Constants.MixinArguments.IN_MAP_FILE_NAMED_INTERMEDIARY, loom.getMappingsProvider().tinyMappings.getCanonicalPath());
put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, loom.getNextMixinMappings().getCanonicalPath());
put(Constants.MixinArguments.OUT_REFMAP_FILE, getRefmapDestination(task, refmapName));
put(Constants.MixinArguments.DEFAULT_OBFUSCATION_ENV, "named:intermediary");
}};
project.getLogger().debug("Outputting refmap to dir: " + getDestinationDir(task) + " for compile task: " + task);
project.getLogger().debug("Outputting refmap to dir: " + getRefmapDestinationDir(task) + " for compile task: " + task);
args.forEach((k, v) -> passArgument(task, k, v));
} catch (IOException e) {
project.getLogger().error("Could not configure mixin annotation processors", e);
@@ -90,7 +100,7 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
LoomGradleExtension extension = LoomGradleExtension.get(project);
if (!extension.ideSync()) {
for (Configuration processorConfig : annotationProcessorConfigurations) {
for (Configuration processorConfig : apConfigurations) {
project.getLogger().info("Adding mixin to classpath of AP config: " + processorConfig.getName());
// Pass named MC classpath to mixin AP classpath
processorConfig.extendsFrom(
@@ -105,14 +115,8 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
}
}
for (T task : invokerTasks) {
passMixinArguments(task);
for (Map.Entry<SourceSet, T> entry : invokerTasks.entrySet()) {
passMixinArguments(entry.getValue(), entry.getKey());
}
}
static Stream<SourceSet> getNonTestSourceSets(Project project) {
return project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets()
.stream()
.filter(sourceSet -> !sourceSet.getName().equals("test"));
}
}

View File

@@ -25,17 +25,30 @@
package net.fabricmc.loom.build.mixin;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.compile.JavaCompile;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.extension.MixinApExtension;
public class JavaApInvoker extends AnnotationProcessorInvoker<JavaCompile> {
public JavaApInvoker(Project project) {
super(project, getConfigurations(project), project.getTasks().withType(JavaCompile.class));
super(
project,
AnnotationProcessorInvoker.getApConfigurations(project, JavaApInvoker::getAptConfigurationName),
getInvokerTasks(project));
}
private static Map<SourceSet, JavaCompile> getInvokerTasks(Project project) {
MixinApExtension mixin = LoomGradleExtension.get(project).getMixinApExtension();
return mixin.getInvokerTasksStream(AnnotationProcessorInvoker.JAVA)
.collect(Collectors.toMap(Map.Entry::getKey, entry -> Objects.requireNonNull((JavaCompile) entry.getValue())));
}
@Override
@@ -44,18 +57,10 @@ public class JavaApInvoker extends AnnotationProcessorInvoker<JavaCompile> {
}
@Override
protected File getDestinationDir(JavaCompile task) {
protected File getRefmapDestinationDir(JavaCompile task) {
return task.getDestinationDir();
}
private static List<Configuration> getConfigurations(Project project) {
// java plugin generates an AP configuration for every source set based off of the getAptConfigurationName method.
return AnnotationProcessorInvoker.getNonTestSourceSets(project)
.map(sourceSet -> project.getConfigurations()
.getByName(getAptConfigurationName(sourceSet.getName()))
).collect(Collectors.toList());
}
private static String getAptConfigurationName(String sourceSet) {
// This is documented by the gradle 4.6 release notes https://docs.gradle.org/4.6/release-notes.html#potential-breaking-changes
return sourceSet.equals("main") ? JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME : sourceSet + "AnnotationProcessor";

View File

@@ -29,18 +29,18 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import kotlin.Unit;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.compile.JavaCompile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.gradle.plugin.KaptExtension;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.extension.MixinApExtension;
public class KaptApInvoker extends AnnotationProcessorInvoker<JavaCompile> {
private final KaptExtension kaptExtension = project.getExtensions().getByType(KaptExtension.class);
@@ -48,7 +48,10 @@ public class KaptApInvoker extends AnnotationProcessorInvoker<JavaCompile> {
private final File dummyRefmapDirectory;
public KaptApInvoker(Project project) {
super(project, getConfigurations(project), project.getTasks().withType(JavaCompile.class));
super(
project,
AnnotationProcessorInvoker.getApConfigurations(project, KaptApInvoker::getKaptConfigurationName),
getInvokerTasks(project));
try {
dummyRefmapDirectory = Files.createTempDirectory("temp_refmap").toFile();
@@ -62,18 +65,26 @@ public class KaptApInvoker extends AnnotationProcessorInvoker<JavaCompile> {
kaptExtension.setIncludeCompileClasspath(false);
}
private static Map<SourceSet, JavaCompile> getInvokerTasks(Project project) {
MixinApExtension mixin = LoomGradleExtension.get(project).getMixinApExtension();
return mixin.getInvokerTasksStream(AnnotationProcessorInvoker.JAVA)
.collect(Collectors.toMap(Map.Entry::getKey, entry -> Objects.requireNonNull((JavaCompile) entry.getValue())));
}
@Override
public void configureMixin() {
super.configureMixin();
for (JavaCompile task : invokerTasks) {
for (Map.Entry<SourceSet, JavaCompile> entry : invokerTasks.entrySet()) {
// Kapt only allows specifying javac args to all annotation processors at once. So we need to specify some dummy
// target location for the refmap and then move it to the correct place for each sourceset
JavaCompile task = entry.getValue();
SourceSet sourceSet = entry.getKey();
task.doLast(t -> {
try {
LoomGradleExtension extension = LoomGradleExtension.get(project);
Path src = Paths.get(getRefmapDestination(task, extension));
Path dest = Paths.get(task.getDestinationDir().toString(), extension.getRefmapName());
String refmapName = Objects.requireNonNull(MixinApExtension.getMixinInformationContainer(sourceSet)).getRefmapName();
Path src = Paths.get(getRefmapDestination(task, refmapName));
Path dest = Paths.get(task.getDestinationDir().toString(), refmapName);
// Possible that no mixin annotations exist
if (Files.exists(src)) {
@@ -87,15 +98,6 @@ public class KaptApInvoker extends AnnotationProcessorInvoker<JavaCompile> {
}
}
@NotNull
private static List<Configuration> getConfigurations(Project project) {
// Kapt generates an AP configuration for every source set based off of the getKaptConfigurationName method.
return AnnotationProcessorInvoker.getNonTestSourceSets(project)
.map(sourceSet -> project.getConfigurations()
.getByName(getKaptConfigurationName(sourceSet.getName()))
).collect(Collectors.toList());
}
// Pulled out from the internal class: https://github.com/JetBrains/kotlin/blob/33a0ec9b4f40f3d6f1f96b2db504ade4c2fafe03/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt#L92
private static String getKaptConfigurationName(String sourceSetName) {
if (!sourceSetName.equals(SourceSet.MAIN_SOURCE_SET_NAME)) {
@@ -116,7 +118,7 @@ public class KaptApInvoker extends AnnotationProcessorInvoker<JavaCompile> {
}
@Override
protected File getDestinationDir(JavaCompile task) {
protected File getRefmapDestinationDir(JavaCompile task) {
return dummyRefmapDirectory;
}
}

View File

@@ -25,17 +25,31 @@
package net.fabricmc.loom.build.mixin;
import java.io.File;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableList;
import org.gradle.api.Project;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.scala.ScalaCompile;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.extension.MixinApExtension;
public class ScalaApInvoker extends AnnotationProcessorInvoker<ScalaCompile> {
public ScalaApInvoker(Project project) {
super(project,
// Scala just uses the java AP configuration afaik. This of course assumes the java AP also gets configured.
ImmutableList.of(),
project.getTasks().withType(ScalaCompile.class));
super(
project,
// Scala just uses the java AP configuration afaik. This of course assumes the java AP also gets configured.
ImmutableList.of(),
getInvokerTasks(project));
}
private static Map<SourceSet, ScalaCompile> getInvokerTasks(Project project) {
MixinApExtension mixin = LoomGradleExtension.get(project).getMixinApExtension();
return mixin.getInvokerTasksStream(AnnotationProcessorInvoker.SCALA)
.collect(Collectors.toMap(Map.Entry::getKey, entry -> Objects.requireNonNull((ScalaCompile) entry.getValue())));
}
@Override
@@ -44,7 +58,7 @@ public class ScalaApInvoker extends AnnotationProcessorInvoker<ScalaCompile> {
}
@Override
protected File getDestinationDir(ScalaCompile task) {
protected File getRefmapDestinationDir(ScalaCompile task) {
return task.getDestinationDir();
}
}

View File

@@ -33,6 +33,7 @@ import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.api.tasks.javadoc.Javadoc;
import org.gradle.jvm.tasks.Jar;
import net.fabricmc.loom.extension.MixinApExtension;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.build.mixin.JavaApInvoker;
import net.fabricmc.loom.build.mixin.KaptApInvoker;
@@ -143,6 +144,9 @@ public final class CompileConfiguration {
System.setProperty("log4j.skipJansi", "true");
project.getLogger().info("Configuring compiler arguments for Java");
MixinApExtension mixinApExtension = LoomGradleExtension.get(project).getMixinApExtension();
mixinApExtension.init();
new JavaApInvoker(project).configureMixin();
if (project.getPluginManager().hasPlugin("scala")) {

View File

@@ -36,6 +36,7 @@ import org.gradle.api.artifacts.Dependency;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.plugins.BasePluginConvention;
import net.fabricmc.loom.api.MixinApExtensionAPI;
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
import net.fabricmc.loom.api.LoomGradleExtensionAPI;
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
@@ -159,6 +160,11 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
return remapMod;
}
@Override
public void mixin(Action<MixinApExtensionAPI> action) {
action.execute(getMixinApExtension());
}
@Override
public void setCustomManifest(String customManifest) {
Objects.requireNonNull(customManifest, "Custom manifest cannot be null");
@@ -174,6 +180,8 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
protected abstract LoomFiles getFiles();
protected abstract MixinApExtension getMixinApExtension();
// This is here to ensure that LoomGradleExtensionApiImpl compiles without any unimplemented methods
private final class EnsureCompile extends LoomGradleExtensionApiImpl {
private EnsureCompile() {
@@ -190,5 +198,10 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
protected LoomFiles getFiles() {
throw new RuntimeException("Yeah... something is really wrong");
}
@Override
protected MixinApExtension getMixinApExtension() {
throw new RuntimeException("Yeah... something is really wrong");
}
}
}

View File

@@ -47,6 +47,7 @@ import net.fabricmc.loom.configuration.processors.JarProcessorManager;
public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implements LoomGradleExtension {
private final Project project;
private final MixinApExtension mixinApExtension;
private final LoomFiles loomFiles;
private final ConfigurableFileCollection unmappedMods;
@@ -62,6 +63,7 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
public LoomGradleExtensionImpl(Project project, LoomFiles files) {
super(project, files);
this.project = project;
this.mixinApExtension = new MixinApExtensionImpl(project);
this.loomFiles = files;
this.unmappedMods = project.files();
}
@@ -160,4 +162,9 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
return provider;
}
@Override
public MixinApExtension getMixinApExtension() {
return this.mixinApExtension;
}
}

View File

@@ -0,0 +1,126 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016-2017 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.extension;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Stream;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.plugins.ExtraPropertiesExtension;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.util.PatternSet;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.api.MixinApExtensionAPI;
/**
* A gradle extension to configure mixin annotation processor.
*/
@ApiStatus.Experimental
public interface MixinApExtension extends MixinApExtensionAPI {
String MIXIN_INFORMATION_CONTAINER = "mixin";
/**
* An information container stores necessary information
* for configuring the mixin annotation processor. It's stored
* in [SourceSet].ext.mixin.
*/
final class MixinInformationContainer {
private final SourceSet sourceSet;
private final String refmapName;
private Stream<String> mixinJsonNames;
final PatternSet mixinJsonPattern;
public MixinInformationContainer(@NotNull SourceSet sourceSet,
@NotNull String refmapName,
@NotNull PatternSet mixinJsonPattern) {
this.sourceSet = sourceSet;
this.refmapName = refmapName;
this.mixinJsonPattern = mixinJsonPattern;
}
void setMixinJsonNames(@NotNull Stream<String> mixinJsonNames) {
if (this.mixinJsonNames == null) {
this.mixinJsonNames = mixinJsonNames;
}
}
@NotNull
public Stream<String> getMixinJsonNames() {
return Objects.requireNonNull(mixinJsonNames);
}
@NotNull
public SourceSet getSourceSet() {
return sourceSet;
}
@NotNull
public String getRefmapName() {
return refmapName;
}
}
@Nullable
static MixinInformationContainer getMixinInformationContainer(SourceSet sourceSet) {
ExtraPropertiesExtension extra = sourceSet.getExtensions().getExtraProperties();
return extra.has(MIXIN_INFORMATION_CONTAINER) ? (MixinInformationContainer) extra.get(MIXIN_INFORMATION_CONTAINER) : null;
}
static void setMixinInformationContainer(SourceSet sourceSet, MixinInformationContainer container) {
ExtraPropertiesExtension extra = sourceSet.getExtensions().getExtraProperties();
if (extra.has(MIXIN_INFORMATION_CONTAINER)) {
throw new InvalidUserDataException("The sourceSet " + sourceSet.getName()
+ " has been configured for mixin annotation processor multiple times");
}
extra.set(MIXIN_INFORMATION_CONTAINER, container);
}
@NotNull
Stream<SourceSet> getMixinSourceSetsStream();
@NotNull
Stream<Configuration> getApConfigurationsStream(Function<String, String> getApConfigNameFunc);
@NotNull
Stream<Map.Entry<SourceSet, Task>> getInvokerTasksStream(String compileTaskLanguage);
@NotNull
@Input
Collection<SourceSet> getMixinSourceSets();
void init();
}

View File

@@ -0,0 +1,110 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.extension;
import org.gradle.api.Action;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.Project;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.util.PatternSet;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.MixinApExtensionAPI;
public abstract class MixinApExtensionApiImpl implements MixinApExtensionAPI {
protected abstract Project getProject();
protected abstract PatternSet add0(SourceSet sourceSet, String refmapName);
@Override
public void add(SourceSet sourceSet, String refmapName, Action<PatternSet> action) {
PatternSet pattern = add0(sourceSet, refmapName);
action.execute(pattern);
}
@Override
public void add(SourceSet sourceSet, String refmapName) {
add(sourceSet, refmapName, x -> { });
}
@Override
public void add(String sourceSetName, String refmapName, Action<PatternSet> action) {
// try to find sourceSet with name sourceSetName in this project
SourceSet sourceSet = getProject().getConvention().getPlugin(JavaPluginConvention.class)
.getSourceSets().findByName(sourceSetName);
if (sourceSet == null) {
throw new InvalidUserDataException("No sourceSet " + sourceSetName + " was found");
}
PatternSet pattern = add0(sourceSet, refmapName);
action.execute(pattern);
}
@Override
public void add(String sourceSetName, String refmapName) {
add(sourceSetName, refmapName, x -> { });
}
@Override
public void add(SourceSet sourceSet, Action<PatternSet> action) {
LoomGradleExtension extension = LoomGradleExtension.get(getProject());
add(sourceSet, extension.getRefmapName(), action);
}
@Override
public void add(SourceSet sourceSet) {
add(sourceSet, x -> { });
}
@Override
public void add(String sourceSetName, Action<PatternSet> action) {
LoomGradleExtension extension = LoomGradleExtension.get(getProject());
add(sourceSetName, extension.getRefmapName(), action);
}
@Override
public void add(String sourceSetName) {
add(sourceSetName, x -> { });
}
// This is here to ensure that LoomGradleExtensionApiImpl compiles without any unimplemented methods
private final class EnsureCompile extends MixinApExtensionApiImpl {
private EnsureCompile() {
super();
throw new RuntimeException();
}
@Override
protected Project getProject() {
throw new RuntimeException("Yeah... something is really wrong");
}
@Override
protected PatternSet add0(SourceSet sourceSet, String refmapName) {
throw new RuntimeException("Yeah... something is really wrong");
}
}
}

View File

@@ -0,0 +1,125 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package net.fabricmc.loom.extension;
import java.io.File;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.UnknownTaskException;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.util.PatternSet;
import org.jetbrains.annotations.NotNull;
public class MixinApExtensionImpl extends MixinApExtensionApiImpl implements MixinApExtension {
private boolean isDefault;
private final Project project;
public MixinApExtensionImpl(Project project) {
this.isDefault = true;
this.project = project;
}
@Override
public Project getProject() {
return this.project;
}
@Override
protected PatternSet add0(SourceSet sourceSet, String refmapName) {
PatternSet pattern = new PatternSet().setIncludes(Collections.singletonList("*.mixins.json"));
MixinApExtension.setMixinInformationContainer(sourceSet, new MixinApExtension.MixinInformationContainer(sourceSet, refmapName, pattern));
isDefault = false;
return pattern;
}
@Override
@NotNull
public Stream<SourceSet> getMixinSourceSetsStream() {
return project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets().stream()
.filter(sourceSet -> {
MixinApExtension.MixinInformationContainer container = MixinApExtension.getMixinInformationContainer(sourceSet);
if (container != null) {
PatternSet pattern = container.mixinJsonPattern;
Stream<String> mixinJsonNames = sourceSet.getResources()
.matching(pattern).getFiles().stream().map(File::getName);
container.setMixinJsonNames(mixinJsonNames);
return true;
}
return false;
});
}
@Override
@NotNull
public Stream<Configuration> getApConfigurationsStream(Function<String, String> getApConfigNameFunc) {
return getMixinSourceSetsStream()
.map(sourceSet -> project.getConfigurations().getByName(getApConfigNameFunc.apply(sourceSet.getName())));
}
@Override
@NotNull
public Stream<Map.Entry<SourceSet, Task>> getInvokerTasksStream(String compileTaskLanguage) {
return getMixinSourceSetsStream()
.flatMap(sourceSet -> {
try {
Task task = project.getTasks().getByName(sourceSet.getCompileTaskName(compileTaskLanguage));
return Stream.of(new AbstractMap.SimpleEntry<>(sourceSet, task));
} catch (UnknownTaskException ignored) {
return Stream.empty();
}
});
}
@Override
@NotNull
@Input
public Collection<SourceSet> getMixinSourceSets() {
return getMixinSourceSetsStream().collect(Collectors.toList());
}
@Override
public void init() {
if (isDefault) {
project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets().forEach(this::add);
}
isDefault = false;
}
}

View File

@@ -170,7 +170,7 @@ public class RemapJarTask extends Jar {
throw new RuntimeException("Failed to remap " + input + " to " + output + " - file missing!");
}
if (MixinRefmapHelper.addRefmapName(extension.getRefmapName(), output)) {
if (MixinRefmapHelper.addRefmapName(project, output)) {
project.getLogger().debug("Transformed mixin reference maps in output JAR!");
}