add modApi, modImplementation, modRuntimeOnly; try to improve source remapping performance

dev/0.11
asie 2019-05-28 09:23:19 +02:00
parent b03b5d2156
commit 754c061e2b
9 changed files with 197 additions and 96 deletions

View File

@ -82,10 +82,11 @@ public class AbstractPlugin implements Plugin<Project> {
// Force add Mojang repository
addMavenRepo(target, "Mojang", "https://libraries.minecraft.net/");
Configuration compileModsConfig = project.getConfigurations().maybeCreate(Constants.COMPILE_MODS);
compileModsConfig.setTransitive(true);
Configuration compileModsMappedConfig = project.getConfigurations().maybeCreate(Constants.COMPILE_MODS_MAPPED);
compileModsMappedConfig.setTransitive(false); // Don't get transitive deps of already remapped mods
Configuration modCompileClasspathConfig = project.getConfigurations().maybeCreate(Constants.MOD_COMPILE_CLASSPATH);
modCompileClasspathConfig.setTransitive(true);
Configuration modCompileClasspathMappedConfig = project.getConfigurations().maybeCreate(Constants.MOD_COMPILE_CLASSPATH_MAPPED);
modCompileClasspathMappedConfig.setTransitive(false);
Configuration minecraftNamedConfig = project.getConfigurations().maybeCreate(Constants.MINECRAFT_NAMED);
minecraftNamedConfig.setTransitive(false); // The launchers do not recurse dependencies
Configuration minecraftIntermediaryConfig = project.getConfigurations().maybeCreate(Constants.MINECRAFT_INTERMEDIARY);
@ -100,18 +101,32 @@ public class AbstractPlugin implements Plugin<Project> {
project.getConfigurations().maybeCreate(Constants.MAPPINGS);
configureIDEs();
configureCompile();
for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) {
Configuration compileModsConfig = project.getConfigurations().maybeCreate(entry.getSourceConfiguration());
compileModsConfig.setTransitive(true);
Configuration compileModsMappedConfig = project.getConfigurations().maybeCreate(entry.getRemappedConfiguration());
compileModsMappedConfig.setTransitive(false); // Don't get transitive deps of already remapped mods
extendsFrom(entry.getTargetConfiguration(project.getConfigurations()), entry.getRemappedConfiguration());
if (entry.isOnModCompileClasspath()) {
extendsFrom(Constants.MOD_COMPILE_CLASSPATH, entry.getSourceConfiguration());
extendsFrom(Constants.MOD_COMPILE_CLASSPATH_MAPPED, entry.getRemappedConfiguration());
}
}
extendsFrom("compile", Constants.MINECRAFT_NAMED);
extendsFrom("annotationProcessor", Constants.MINECRAFT_NAMED);
extendsFrom("annotationProcessor", Constants.MOD_COMPILE_CLASSPATH_MAPPED);
extendsFrom(Constants.MINECRAFT_NAMED, Constants.MINECRAFT_DEPENDENCIES);
extendsFrom(Constants.MINECRAFT_INTERMEDIARY, Constants.MINECRAFT_DEPENDENCIES);
extendsFrom(Constants.COMPILE_MODS_MAPPED, Constants.MINECRAFT_NAMED);
extendsFrom("compile", Constants.COMPILE_MODS_MAPPED);
extendsFrom("compile", Constants.MAPPINGS);
extendsFrom("annotationProcessor", Constants.COMPILE_MODS_MAPPED);
extendsFrom("annotationProcessor", Constants.MAPPINGS);
configureIDEs();
configureCompile();
Map<Project, Set<Task>> taskMap = project.getAllTasks(true);
for (Map.Entry<Project, Set<Task>> entry : taskMap.entrySet()) {
Project project = entry.getKey();
@ -331,45 +346,51 @@ public class AbstractPlugin implements Plugin<Project> {
protected void configureMaven() {
project.afterEvaluate((p) -> {
Configuration compileModsConfig = p.getConfigurations().getByName(Constants.COMPILE_MODS);
for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) {
if (!entry.hasMavenScope()) {
continue;
}
// add modsCompile to maven-publish
PublishingExtension mavenPublish = p.getExtensions().findByType(PublishingExtension.class);
if (mavenPublish != null) {
mavenPublish.publications((publications) -> {
for (Publication publication : publications) {
if (publication instanceof MavenPublication) {
((MavenPublication) publication).pom((pom) -> {
pom.withXml((xml) -> {
Node dependencies = GroovyXmlUtil.getOrCreateNode(xml.asNode(), "dependencies");
Set<String> foundArtifacts = new HashSet<>();
Configuration compileModsConfig = p.getConfigurations().getByName(entry.getSourceConfiguration());
GroovyXmlUtil.childrenNodesStream(dependencies)
.filter((n) -> "dependency".equals(n.name()))
.forEach((n) -> {
Optional<Node> groupId = GroovyXmlUtil.getNode(n, "groupId");
Optional<Node> artifactId = GroovyXmlUtil.getNode(n, "artifactId");
if (groupId.isPresent() && artifactId.isPresent()) {
foundArtifacts.add(groupId.get().text() + ":" + artifactId.get().text());
}
});
// add modsCompile to maven-publish
PublishingExtension mavenPublish = p.getExtensions().findByType(PublishingExtension.class);
if (mavenPublish != null) {
mavenPublish.publications((publications) -> {
for (Publication publication : publications) {
if (publication instanceof MavenPublication) {
((MavenPublication) publication).pom((pom) -> {
pom.withXml((xml) -> {
Node dependencies = GroovyXmlUtil.getOrCreateNode(xml.asNode(), "dependencies");
Set<String> foundArtifacts = new HashSet<>();
for (Dependency dependency : compileModsConfig.getAllDependencies()) {
if (foundArtifacts.contains(dependency.getGroup() + ":" + dependency.getName())) {
continue;
GroovyXmlUtil.childrenNodesStream(dependencies)
.filter((n) -> "dependency".equals(n.name()))
.forEach((n) -> {
Optional<Node> groupId = GroovyXmlUtil.getNode(n, "groupId");
Optional<Node> artifactId = GroovyXmlUtil.getNode(n, "artifactId");
if (groupId.isPresent() && artifactId.isPresent()) {
foundArtifacts.add(groupId.get().text() + ":" + artifactId.get().text());
}
});
for (Dependency dependency : compileModsConfig.getAllDependencies()) {
if (foundArtifacts.contains(dependency.getGroup() + ":" + dependency.getName())) {
continue;
}
Node depNode = dependencies.appendNode("dependency");
depNode.appendNode("groupId", dependency.getGroup());
depNode.appendNode("artifactId", dependency.getName());
depNode.appendNode("version", dependency.getVersion());
depNode.appendNode("scope", entry.getMavenScope());
}
Node depNode = dependencies.appendNode("dependency");
depNode.appendNode("groupId", dependency.getGroup());
depNode.appendNode("artifactId", dependency.getName());
depNode.appendNode("version", dependency.getVersion());
depNode.appendNode("scope", "compile");
}
});
});
});
}
}
}
});
});
}
}
});
}

View File

@ -30,6 +30,7 @@ import net.fabricmc.loom.providers.MinecraftMappedProvider;
import net.fabricmc.loom.providers.MinecraftProvider;
import net.fabricmc.loom.util.LoomDependencyManager;
import org.cadixdev.lorenz.MappingSet;
import org.cadixdev.mercury.Mercury;
import org.gradle.api.Project;
import org.gradle.api.UnknownDomainObjectException;
import org.gradle.api.artifacts.Configuration;
@ -62,11 +63,16 @@ public class LoomGradleExtension {
private JsonObject installerJson;
private int installerJsonPriority = Integer.MAX_VALUE; // 0+, higher = less prioritized
private MappingSet[] srcMappingCache = new MappingSet[2];
private Mercury[] srcMercuryCache = new Mercury[2];
public MappingSet getOrCreateSrcMappingCache(int id, Supplier<MappingSet> factory) {
return srcMappingCache[id] != null ? srcMappingCache[id] : (srcMappingCache[id] = factory.get());
}
public Mercury getOrCreateSrcMercuryCache(int id, Supplier<Mercury> factory) {
return srcMercuryCache[id] != null ? srcMercuryCache[id] : (srcMercuryCache[id] = factory.get());
}
public LoomGradleExtension(Project project) {
this.project = project;
}

View File

@ -107,7 +107,7 @@ public class MigrateMappingsTask extends AbstractLoomTask {
mercury.getClassPath().add(file.toPath());
}
for (File file : project.getConfigurations().getByName(Constants.COMPILE_MODS_MAPPED).getFiles()) {
for (File file : project.getConfigurations().getByName("compileClasspath").getFiles()) {
mercury.getClassPath().add(file.toPath());
}

View File

@ -25,6 +25,10 @@
package net.fabricmc.loom.util;
import com.google.common.collect.ImmutableList;
import java.util.List;
public class Constants {
public static final String DEFAULT_FABRIC_CLIENT_TWEAKER = "net.fabricmc.loader.launch.FabricClientTweaker";
@ -35,8 +39,15 @@ public class Constants {
public static final String SYSTEM_ARCH = System.getProperty("os.arch").equals("64") ? "64" : "32";
public static final String COMPILE_MODS = "modCompile";
public static final String COMPILE_MODS_MAPPED = "modCompileMapped";
public static final String MOD_COMPILE_CLASSPATH = "modCompileClasspath";
public static final String MOD_COMPILE_CLASSPATH_MAPPED = "modCompileClasspathMapped";
public static final List<RemappedConfigurationEntry> MOD_COMPILE_ENTRIES = ImmutableList.of(
new RemappedConfigurationEntry("modCompile", "compile", true, "compile"),
new RemappedConfigurationEntry("modApi", "api", true, "compile"),
new RemappedConfigurationEntry("modImplementation", "implementation", true, "runtime"),
new RemappedConfigurationEntry("modRuntime", "runtimeOnly", false, "")
);
public static final String INCLUDE = "include";
public static final String MINECRAFT = "minecraft";
public static final String MINECRAFT_DEPENDENCIES = "minecraftLibraries";

View File

@ -110,20 +110,24 @@ public class LoomDependencyManager {
});
}
ModCompileRemapper.remapDependencies(
project,
mappingsProvider.mappingsName + "." + mappingsProvider.mappingsVersion,
extension,
project.getConfigurations().getByName(Constants.COMPILE_MODS),
project.getConfigurations().getByName(Constants.COMPILE_MODS_MAPPED),
project.getConfigurations().getByName("compile"),
afterTasks::add
);
{
String mappingsKey = mappingsProvider.mappingsName + "." + mappingsProvider.mappingsVersion;
for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) {
ModCompileRemapper.remapDependencies(
project, mappingsKey, extension,
project.getConfigurations().getByName(entry.getSourceConfiguration()),
project.getConfigurations().getByName(entry.getRemappedConfiguration()),
project.getConfigurations().getByName(entry.getTargetConfiguration(project.getConfigurations())),
afterTasks::add
);
}
}
if (extension.getInstallerJson() == null) {
//If we've not found the installer JSON we've probably skipped remapping Fabric loader, let's go looking
project.getLogger().info("Didn't find installer JSON, searching through compileMods");
Configuration configuration = project.getConfigurations().getByName(Constants.COMPILE_MODS);
project.getLogger().info("Didn't find installer JSON, searching through modCompileClasspath");
Configuration configuration = project.getConfigurations().getByName(Constants.MOD_COMPILE_CLASSPATH);
Set<File> seenFiles = new HashSet<>();

View File

@ -82,7 +82,7 @@ public class ModCompileRemapper {
File modStore = extension.getRemappedModCache();
remapArtifact(project, artifact, remappedFilename, modStore);
remapArtifact(project, modCompileRemapped, artifact, remappedFilename, modStore);
project.getDependencies().add(modCompileRemapped.getName(), project.getDependencies().module(remappedNotation));
@ -118,13 +118,13 @@ public class ModCompileRemapper {
dependencies.add(regularCompile.getName(), dep);
}
private static void remapArtifact(Project project, ResolvedArtifact artifact, String remappedFilename, File modStore) {
private static void remapArtifact(Project project, Configuration config, ResolvedArtifact artifact, String remappedFilename, File modStore) {
File input = artifact.getFile();
File output = new File(modStore, remappedFilename + ".jar");
if (!output.exists() || input.lastModified() <= 0 || input.lastModified() > output.lastModified()) {
//If the output doesn't exist, or appears to be outdated compared to the input we'll remap it
try {
ModProcessor.handleMod(input, output, project);
ModProcessor.processMod(input, output, project, config);
} catch (IOException e) {
throw new RuntimeException("Failed to remap mod", e);
}
@ -137,6 +137,8 @@ public class ModCompileRemapper {
} else {
project.getLogger().info(output.getName() + " is up to date with " + input.getName());
}
ModProcessor.acknowledgeMod(input, output, project, config);
}
private static File findSources(DependencyHandler dependencies, ResolvedArtifact artifact) {

View File

@ -32,9 +32,9 @@ import net.fabricmc.loom.providers.MappingsProvider;
import net.fabricmc.loom.providers.MinecraftMappedProvider;
import net.fabricmc.tinyremapper.OutputConsumerPath;
import net.fabricmc.tinyremapper.TinyRemapper;
import net.fabricmc.tinyremapper.TinyUtils;
import org.apache.commons.io.IOUtils;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.internal.impldep.aQute.lib.strings.Strings;
import org.zeroturnaround.zip.ZipUtil;
import org.zeroturnaround.zip.commons.FileUtils;
@ -48,7 +48,8 @@ import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
@ -56,21 +57,24 @@ import java.util.zip.ZipEntry;
public class ModProcessor {
private static final Gson GSON = new Gson();
public static void handleMod(File input, File output, Project project) throws IOException {
public static void processMod(File input, File output, Project project, Configuration config) throws IOException {
if(output.exists()){
output.delete();
}
remapJar(input, output, project);
readInstallerJson(input, project);
//Enable this if you want your nested jars to be extracted, this will extract **all** jars
if(project.getExtensions().getByType(LoomGradleExtension.class).extractJars){
handleNestedJars(input, project);
handleNestedJars(input, project, config);
}
//Always strip the nested jars
stripNestedJars(output);
}
private static void handleNestedJars(File input, Project project) throws IOException {
public static void acknowledgeMod(File input, File output, Project project, Configuration config) {
readInstallerJson(input, project);
}
private static void handleNestedJars(File input, Project project, Configuration config) throws IOException {
JarFile jarFile = new JarFile(input);
JarEntry modJsonEntry = jarFile.getJarEntry("fabric.mod.json");
if(modJsonEntry == null){
@ -86,12 +90,12 @@ public class ModProcessor {
JsonObject jsonObject = jsonArray.get(i).getAsJsonObject();
String fileName = jsonObject.get("file").getAsString();
project.getLogger().lifecycle(String.format("Found %s nested in %s", fileName, input.getName()));
processNestedJar(jarFile, fileName, project);
processNestedJar(jarFile, fileName, project, config);
}
}
}
private static void processNestedJar(JarFile parentJar, String fileName, Project project) throws IOException {
private static void processNestedJar(JarFile parentJar, String fileName, Project project, Configuration config) throws IOException {
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
JarEntry entry = parentJar.getJarEntry(fileName);
@ -105,14 +109,14 @@ public class ModProcessor {
}
File remappedFile = new File(extension.getRemappedModCache(), fileName.substring(fileName.lastIndexOf("/")));
handleMod(nestedFile, remappedFile, project);
processMod(nestedFile, remappedFile, project, config);
if(!remappedFile.exists()){
throw new RuntimeException("Failed to find processed nested jar");
}
//Add the project right onto the remapped mods, hopefully this works
project.getDependencies().add(Constants.COMPILE_MODS_MAPPED, project.files(remappedFile));
project.getDependencies().add(config.getName(), project.files(remappedFile));
}
private static void stripNestedJars(File file){
@ -142,16 +146,20 @@ public class ModProcessor {
Path[] mcDeps = mappedProvider.getMapperPaths().stream()
.map(File::toPath)
.toArray(Path[]::new);
Path[] modCompiles = project.getConfigurations().getByName(Constants.COMPILE_MODS).getFiles().stream()
.filter((f) -> !f.equals(input))
.map(p -> {
if (p.equals(input)) {
return inputPath;
} else {
return p.toPath();
}
})
.toArray(Path[]::new);
Set<Path> modCompiles = new HashSet<>();
for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) {
project.getConfigurations().getByName(entry.getSourceConfiguration()).getFiles().stream()
.filter((f) -> !f.equals(input))
.map(p -> {
if (p.equals(input)) {
return inputPath;
} else {
return p.toPath();
}
})
.forEach(modCompiles::add);
}
project.getLogger().lifecycle(":remapping " + input.getName() + " (TinyRemapper, " + fromM + " -> " + toM + ")");
@ -161,7 +169,7 @@ public class ModProcessor {
try (OutputConsumerPath outputConsumer = new OutputConsumerPath(Paths.get(output.getAbsolutePath()))) {
outputConsumer.addNonClassFiles(inputPath);
remapper.readClassPath(modCompiles);
remapper.readClassPath(modCompiles.toArray(new Path[0]));
remapper.readClassPath(mc);
remapper.readClassPath(mcDeps);
remapper.readInputs(inputPath);
@ -194,7 +202,7 @@ public class ModProcessor {
if (entry == null) {
entry = jarFile.getEntry("fabric-installer.json");
priority = 1;
priority++;
if (entry == null) {
return;
}

View File

@ -0,0 +1,45 @@
package net.fabricmc.loom.util;
import org.gradle.api.artifacts.ConfigurationContainer;
public class RemappedConfigurationEntry {
private final String sourceConfiguration;
private final String targetConfiguration;
private final String mavenScope;
private final boolean isOnModCompileClasspath;
public RemappedConfigurationEntry(String sourceConfiguration, String targetConfiguration, boolean isOnModCompileClasspath, String mavenScope) {
this.sourceConfiguration = sourceConfiguration;
this.targetConfiguration = targetConfiguration;
this.isOnModCompileClasspath = isOnModCompileClasspath;
this.mavenScope = mavenScope;
}
public String getMavenScope() {
return mavenScope;
}
public boolean hasMavenScope() {
return mavenScope != null && !mavenScope.isEmpty();
}
public boolean isOnModCompileClasspath() {
return isOnModCompileClasspath;
}
public String getSourceConfiguration() {
return sourceConfiguration;
}
public String getRemappedConfiguration() {
return sourceConfiguration + "Mapped";
}
public String getTargetConfiguration(ConfigurationContainer container) {
if (container.findByName(targetConfiguration) == null) {
return "compile";
}
return targetConfiguration;
}
}

View File

@ -73,26 +73,30 @@ public class SourceRemapper {
project.getLogger().lifecycle(":remapping source jar");
Mercury mercury = new Mercury();
Mercury mercury = extension.getOrCreateSrcMercuryCache(toNamed ? 1 : 0, () -> {
Mercury m = new Mercury();
for (File file : project.getConfigurations().getByName(Constants.MINECRAFT_DEPENDENCIES).getFiles()) {
mercury.getClassPath().add(file.toPath());
}
if (!toNamed) {
for (File file : project.getConfigurations().getByName(Constants.COMPILE_MODS_MAPPED).getFiles()) {
mercury.getClassPath().add(file.toPath());
for (File file : project.getConfigurations().getByName(Constants.MINECRAFT_DEPENDENCIES).getFiles()) {
m.getClassPath().add(file.toPath());
}
}
for (Path file : extension.getUnmappedMods()) {
if (Files.isRegularFile(file)) {
mercury.getClassPath().add(file);
if (!toNamed) {
for (File file : project.getConfigurations().getByName("compileClasspath").getFiles()) {
m.getClassPath().add(file.toPath());
}
}
for (Path file : extension.getUnmappedMods()) {
if (Files.isRegularFile(file)) {
m.getClassPath().add(file);
}
}
}
mercury.getClassPath().add(extension.getMinecraftMappedProvider().MINECRAFT_MAPPED_JAR.toPath());
mercury.getClassPath().add(extension.getMinecraftMappedProvider().MINECRAFT_INTERMEDIARY_JAR.toPath());
m.getClassPath().add(extension.getMinecraftMappedProvider().MINECRAFT_MAPPED_JAR.toPath());
m.getClassPath().add(extension.getMinecraftMappedProvider().MINECRAFT_INTERMEDIARY_JAR.toPath());
mercury.getProcessors().add(MercuryRemapper.create(mappings));
m.getProcessors().add(MercuryRemapper.create(mappings));
return m;
});
if (source.equals(destination)) {
if (source.isDirectory()) {