More changes

This commit is contained in:
modmuss50
2022-10-04 20:46:46 +01:00
parent ab4234330e
commit 24b727c84c
14 changed files with 221 additions and 93 deletions

View File

@@ -71,6 +71,8 @@ public interface LoomGradleExtensionAPI {
ListProperty<MinecraftJarProcessor<?>> getMinecraftJarProcessors();
void addMinecraftJarProcessor(Class<? extends MinecraftJarProcessor<?>> clazz, Object... parameters);
ConfigurableFileCollection getLog4jConfigs();
Dependency officialMojangMappings();

View File

@@ -0,0 +1,28 @@
/*
* 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.api.processor;
public interface MappingProcessorContext {
}

View File

@@ -44,10 +44,10 @@ public interface MinecraftJarProcessor<S extends MinecraftJarProcessor.Spec> ext
}
interface Spec {
String cacheValue();
// Must make sure hashCode is correctly implemented.
}
interface MappingsProcessor<S> {
boolean transform(MemoryMappingTree mappings, S spec, ProcessorContext context);
boolean transform(MemoryMappingTree mappings, S spec, MappingProcessorContext context);
}
}

View File

@@ -25,11 +25,16 @@
package net.fabricmc.loom.api.processor;
import java.util.List;
import java.util.stream.Stream;
import net.fabricmc.loom.util.fmj.FabricModJson;
public interface SpecContext {
List<FabricModJson> getModDependencies();
List<FabricModJson> modDependencies();
List<FabricModJson> getMods();
List<FabricModJson> localMods();
default List<FabricModJson> allMods() {
return Stream.concat(modDependencies().stream(), localMods().stream()).toList();
}
}

View File

@@ -51,7 +51,6 @@ import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerJarP
import net.fabricmc.loom.configuration.ifaceinject.InterfaceInjectionProcessor;
import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager;
import net.fabricmc.loom.configuration.processors.ModJavadocProcessor;
import net.fabricmc.loom.configuration.processors.SpecContextImpl;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
@@ -198,7 +197,7 @@ public final class CompileConfiguration {
NamedMinecraftProvider<?> namedMinecraftProvider = jarConfiguration.getNamedMinecraftProviderBiFunction().apply(project, minecraftProvider);
registerGameProcessors(project);
MinecraftJarProcessorManager minecraftJarProcessorManager = MinecraftJarProcessorManager.create(extension.getMinecraftJarProcessors().get(), new SpecContextImpl());
MinecraftJarProcessorManager minecraftJarProcessorManager = MinecraftJarProcessorManager.create(project);
if (minecraftJarProcessorManager != null) {
// Wrap the named MC provider for one that will provide the processed jars
@@ -235,14 +234,7 @@ public final class CompileConfiguration {
}
}
if (extension.getEnableModProvidedJavadoc().get()) {
// This doesn't do any processing on the compiled jar, but it does have an effect on the generated sources.
final ModJavadocProcessor javadocProcessor = ModJavadocProcessor.create(project);
if (javadocProcessor != null) {
extension.getGameJarProcessors().add(javadocProcessor);
}
}
extension.addMinecraftJarProcessor(ModJavadocProcessor.class, "fabric-loom:mod-javadoc");
}
private static void setupMixinAp(Project project, MixinExtension mixin) {

View File

@@ -71,9 +71,6 @@ import net.fabricmc.mappingio.tree.MemoryMappingTree;
import net.fabricmc.tinyremapper.TinyRemapper;
public class InterfaceInjectionProcessor implements JarProcessor, GenerateSourcesTask.MappingsProcessor {
// Filename used to store hash of injected interfaces in processed jar file
private static final String HASH_FILENAME = "injected_interfaces.sha256";
private final Map<String, List<InjectedInterface>> injectedInterfaces;
private final Project project;
private final LoomGradleExtension extension;
@@ -200,7 +197,7 @@ public class InterfaceInjectionProcessor implements JarProcessor, GenerateSource
final FabricModJson fabricModJson;
try {
fabricModJson = FabricModJsonFactory.createFromSourceSetNullable(sourceSet);
fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(sourceSet);
} catch (IOException e) {
throw new UncheckedIOException(e);
}

View File

@@ -36,8 +36,11 @@ import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.gradle.api.Project;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.processor.MappingProcessorContext;
import net.fabricmc.loom.api.processor.MinecraftJarProcessor;
import net.fabricmc.loom.api.processor.ProcessorContext;
import net.fabricmc.loom.api.processor.SpecContext;
@@ -53,6 +56,12 @@ public final class MinecraftJarProcessorManager {
this.jarProcessors = Collections.unmodifiableList(jarProcessors);
}
@Nullable
public static MinecraftJarProcessorManager create(Project project) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
return MinecraftJarProcessorManager.create(extension.getMinecraftJarProcessors().get(), SpecContextImpl.create(project));
}
@Nullable
public static MinecraftJarProcessorManager create(List<MinecraftJarProcessor<?>> processors, SpecContext context) {
List<ProcessorEntry<?>> entries = new ArrayList<>();
@@ -114,10 +123,16 @@ public final class MinecraftJarProcessorManager {
ZipUtils.add(jar, CACHE_VALUE_FILE_PATH, getCacheValue());
}
public void processMappings(MemoryMappingTree mappings, ProcessorContext context) {
public boolean processMappings(MemoryMappingTree mappings, MappingProcessorContext context) {
boolean transformed = false;
for (ProcessorEntry<?> entry : jarProcessors) {
entry.processMappings(mappings, context);
if (entry.processMappings(mappings, context)) {
transformed = true;
}
}
return transformed;
}
record ProcessorEntry<S extends MinecraftJarProcessor.Spec>(S spec, MinecraftJarProcessor<S> processor, @Nullable MinecraftJarProcessor.MappingsProcessor<S> mappingsProcessor) {
@@ -130,8 +145,8 @@ public final class MinecraftJarProcessorManager {
processor().processJar(jar, spec, context);
}
private void processMappings(MemoryMappingTree mappings, ProcessorContext context) {
mappingsProcessor().transform(mappings, spec, context);
private boolean processMappings(MemoryMappingTree mappings, MappingProcessorContext context) {
return mappingsProcessor().transform(mappings, spec, context);
}
private String name() {
@@ -139,7 +154,7 @@ public final class MinecraftJarProcessorManager {
}
private String cacheValue() {
return processor.getName() + ":" + spec.cacheValue();
return processor.getName() + ":" + spec.hashCode();
}
}
}

View File

@@ -25,15 +25,16 @@
package net.fabricmc.loom.configuration.processors;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import com.google.gson.JsonElement;
import org.gradle.api.Project;
@@ -42,50 +43,49 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.RemapConfigurationSettings;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.task.GenerateSourcesTask;
import net.fabricmc.loom.api.processor.MinecraftJarProcessor;
import net.fabricmc.loom.api.processor.ProcessorContext;
import net.fabricmc.loom.api.processor.SpecContext;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.ZipUtils;
import net.fabricmc.loom.util.fmj.FabricModJson;
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
import net.fabricmc.mappingio.MappingReader;
import net.fabricmc.mappingio.tree.MappingTree;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
public final class ModJavadocProcessor implements JarProcessor, GenerateSourcesTask.MappingsProcessor {
public abstract class ModJavadocProcessor implements MinecraftJarProcessor<ModJavadocProcessor.Spec> {
private static final Logger LOGGER = LoggerFactory.getLogger(ModJavadocProcessor.class);
private final List<ModJavadoc> javadocs;
@Inject
public abstract Project getProject();
private ModJavadocProcessor(List<ModJavadoc> javadocs) {
this.javadocs = javadocs;
private final String name;
@Inject
public ModJavadocProcessor(String name) {
this.name = name;
}
@Nullable
public static ModJavadocProcessor create(Project project) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final List<ModJavadoc> javadocs = new ArrayList<>();
@Override
public String getName() {
return name;
}
for (RemapConfigurationSettings entry : extension.getRemapConfigurations()) {
final Set<File> artifacts = entry.getSourceConfiguration().get().resolve();
@Override
public @Nullable ModJavadocProcessor.Spec buildSpec(SpecContext context) {
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
for (File artifact : artifacts) {
if (!FabricModJsonFactory.isModJar(artifact.toPath())) {
continue;
}
if (!extension.getEnableModProvidedJavadoc().get()) {
return null;
}
final ModJavadoc modJavadoc;
List<ModJavadoc> javadocs = new ArrayList<>();
try {
modJavadoc = ModJavadoc.fromModJar(artifact.toPath());
} catch (IOException e) {
throw new UncheckedIOException("Failed to read mod jar (%s)".formatted(artifact), e);
}
for (FabricModJson fabricModJson : context.allMods()) {
ModJavadoc javadoc = ModJavadoc.create(fabricModJson);
if (modJavadoc != null) {
javadocs.add(modJavadoc);
}
if (javadoc != null) {
javadocs.add(javadoc);
}
}
@@ -93,36 +93,31 @@ public final class ModJavadocProcessor implements JarProcessor, GenerateSourcesT
return null;
}
return new ModJavadocProcessor(javadocs);
return new Spec(Collections.unmodifiableList(javadocs));
}
public record Spec(List<ModJavadoc> javadocs) implements MinecraftJarProcessor.Spec {
}
@Override
public boolean transform(MemoryMappingTree mappings) {
for (ModJavadoc javadoc : javadocs) {
javadoc.apply(mappings);
}
return true;
public void processJar(Path jar, Spec spec, ProcessorContext context) {
// Nothing to do for the jar
}
@Override
public String getId() {
return "loom:interface_injection:" + javadocs.hashCode();
}
public @Nullable MappingsProcessor<Spec> processMappings() {
return (mappings, spec, context) -> {
for (ModJavadoc javadoc : spec.javadocs()) {
javadoc.apply(mappings);
}
@Override
public void setup() {
}
@Override
public void process(File file) {
// No need to actually process anything, we need to be a JarProcessor to ensure that the jar is cached correctly.
return true;
};
}
public record ModJavadoc(String modId, MemoryMappingTree mappingTree) {
@Nullable
public static ModJavadoc fromModJar(Path path) throws IOException {
final FabricModJson fabricModJson = FabricModJsonFactory.createFromZip(path);
public static ModJavadoc create(FabricModJson fabricModJson) {
final String modId = fabricModJson.getId();
final JsonElement customElement = fabricModJson.getCustom(Constants.CustomModJsonKeys.PROVIDED_JAVADOC);
@@ -131,11 +126,16 @@ public final class ModJavadocProcessor implements JarProcessor, GenerateSourcesT
}
final String javaDocPath = customElement.getAsString();
final byte[] data = ZipUtils.unpack(path, javaDocPath);
final MemoryMappingTree mappings = new MemoryMappingTree();
try (Reader reader = new InputStreamReader(new ByteArrayInputStream(data))) {
MappingReader.read(reader, mappings);
try {
final byte[] data = fabricModJson.getSource().read(javaDocPath);
try (Reader reader = new InputStreamReader(new ByteArrayInputStream(data))) {
MappingReader.read(reader, mappings);
}
} catch (IOException e) {
throw new UncheckedIOException("Failed to read javadoc from mod: " + modId, e);
}
if (!mappings.getSrcNamespace().equals(MappingsNamespace.INTERMEDIARY.toString())) {

View File

@@ -24,21 +24,85 @@
package net.fabricmc.loom.configuration.processors;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import org.gradle.api.Project;
import org.gradle.api.tasks.SourceSet;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.RemapConfigurationSettings;
import net.fabricmc.loom.api.processor.SpecContext;
import net.fabricmc.loom.util.fmj.FabricModJson;
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
import net.fabricmc.loom.util.gradle.SourceSetHelper;
public class SpecContextImpl implements SpecContext {
@Override
public List<FabricModJson> getModDependencies() {
// TODO
return null;
/**
* @param modDependencies External mods that are depended on
* @param localMods The main mod being built. In the future this may also include other mods.
*/
public record SpecContextImpl(List<FabricModJson> modDependencies, List<FabricModJson> localMods) implements SpecContext {
public static SpecContextImpl create(Project project) {
return new SpecContextImpl(getDependentMods(project), getMods(project));
}
@Override
public List<FabricModJson> getMods() {
// TODO
return null;
private static List<FabricModJson> getDependentMods(Project project) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
var mods = new ArrayList<FabricModJson>();
for (RemapConfigurationSettings entry : extension.getRemapConfigurations()) {
final Set<File> artifacts = entry.getSourceConfiguration().get().resolve();
for (File artifact : artifacts) {
final FabricModJson fabricModJson;
try {
fabricModJson = FabricModJsonFactory.createFromZipNullable(artifact.toPath());
} catch (IOException e) {
throw new UncheckedIOException("Failed to read dependent mod jar: " + artifact, e);
}
if (fabricModJson != null) {
mods.add(fabricModJson);
}
}
}
// TODO supporting projects here should magically allow TAWs and what not to work across project deps :)
return sorted(mods);
}
private static List<FabricModJson> getMods(Project project) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
var sourceSets = new ArrayList<SourceSet>();
sourceSets.add(SourceSetHelper.getMainSourceSet(project));
if (extension.areEnvironmentSourceSetsSplit()) {
sourceSets.add(SourceSetHelper.getSourceSetByName("client", project));
}
try {
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(sourceSets.toArray(SourceSet[]::new));
if (fabricModJson != null) {
return List.of(fabricModJson);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return Collections.emptyList();
}
// Sort to ensure stable caching
private static List<FabricModJson> sorted(List<FabricModJson> mods) {
return mods.stream().sorted(Comparator.comparing(FabricModJson::getId)).toList();
}
}

View File

@@ -173,7 +173,6 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
@Override
public ListProperty<JarProcessor> getGameJarProcessors() {
getDeprecationHelper().replaceWithInLoom2_0("getGameJarProcessors", "getMinecraftJarProcessors");
return jarProcessors;
}
@@ -188,6 +187,11 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
return minecraftJarProcessors;
}
@Override
public void addMinecraftJarProcessor(Class<? extends MinecraftJarProcessor<?>> clazz, Object... parameters) {
getMinecraftJarProcessors().add(getProject().getObjects().newInstance(clazz, parameters));
}
@Override
public Dependency officialMojangMappings() {
if (layeredSpecBuilderScope.get()) {

View File

@@ -64,9 +64,10 @@ import net.fabricmc.loom.api.decompilers.DecompilationMetadata;
import net.fabricmc.loom.api.decompilers.DecompilerOptions;
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.api.processor.MappingProcessorContext;
import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerMappingsProcessor;
import net.fabricmc.loom.configuration.ifaceinject.InterfaceInjectionProcessor;
import net.fabricmc.loom.configuration.processors.ModJavadocProcessor;
import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager;
import net.fabricmc.loom.decompilers.LineNumberRemapper;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.FileSystemUtil;
@@ -338,10 +339,10 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
mappingsProcessors.add(new InterfaceInjectionProcessor(getProject()));
}
final ModJavadocProcessor javadocProcessor = ModJavadocProcessor.create(getProject());
MinecraftJarProcessorManager minecraftJarProcessorManager = MinecraftJarProcessorManager.create(getProject());
if (javadocProcessor != null) {
mappingsProcessors.add(javadocProcessor);
if (minecraftJarProcessorManager != null) {
mappingsProcessors.add(mappings -> minecraftJarProcessorManager.processMappings(mappings, new MappingProcessorContextImpl()));
}
if (mappingsProcessors.isEmpty()) {
@@ -392,4 +393,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
throw new RuntimeException(e);
}
}
private static class MappingProcessorContextImpl implements MappingProcessorContext {
}
}

View File

@@ -94,15 +94,15 @@ public final class FabricModJsonFactory {
}
@Nullable
public static FabricModJson createFromSourceSetNullable(SourceSet sourceSet) throws IOException {
final File file = SourceSetHelper.findFileInResource(sourceSet, FABRIC_MOD_JSON);
public static FabricModJson createFromSourceSetsNullable(SourceSet... sourceSets) throws IOException {
final File file = SourceSetHelper.findFirstFileInResource(FABRIC_MOD_JSON, sourceSets);
if (file == null) {
return null;
}
try (Reader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
return create(LoomGradlePlugin.GSON.fromJson(reader, JsonObject.class), new FabricModJsonSource.SourceSetSource(sourceSet));
return create(LoomGradlePlugin.GSON.fromJson(reader, JsonObject.class), new FabricModJsonSource.SourceSetSource(sourceSets));
}
}

View File

@@ -56,10 +56,10 @@ public interface FabricModJsonSource {
}
}
record SourceSetSource(SourceSet sourceSet) implements FabricModJsonSource {
record SourceSetSource(SourceSet... sourceSets) implements FabricModJsonSource {
@Override
public byte[] read(String path) throws IOException {
final File file = SourceSetHelper.findFileInResource(sourceSet, path);
final File file = SourceSetHelper.findFirstFileInResource(path, sourceSets);
if (file == null) {
throw new FileNotFoundException("Could not find: " + path);

View File

@@ -33,6 +33,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
@@ -275,6 +276,9 @@ public final class SourceSetHelper {
@Nullable
public static File findFileInResource(SourceSet sourceSet, String path) {
Objects.requireNonNull(sourceSet);
Objects.requireNonNull(path);
try {
return sourceSet.getResources()
.matching(patternFilterable -> patternFilterable.include(path))
@@ -284,4 +288,17 @@ public final class SourceSetHelper {
return null;
}
}
@Nullable
public static File findFirstFileInResource(String path, SourceSet... sourceSets) {
for (SourceSet sourceSet : sourceSets) {
File file = findFileInResource(sourceSet, path);
if (file != null) {
return file;
}
}
return null;
}
}