Mod Remapping Refactor. (#362)

Improved gradle 7 support
General cleanup
dev/0.11
modmuss50 2021-03-12 22:16:24 +00:00 committed by GitHub
parent e9c7c21ede
commit 7231b9e053
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 689 additions and 356 deletions

View File

@ -0,0 +1,95 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016, 2017, 2018 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.build.nesting;
import java.io.File;
import java.util.Collection;
import java.util.zip.ZipEntry;
import com.google.common.base.Preconditions;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.gradle.api.logging.Logger;
import org.zeroturnaround.zip.FileSource;
import org.zeroturnaround.zip.ZipEntrySource;
import org.zeroturnaround.zip.ZipUtil;
import org.zeroturnaround.zip.transform.StringZipEntryTransformer;
import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry;
import net.fabricmc.loom.LoomGradlePlugin;
import net.fabricmc.loom.util.ModUtils;
public class JarNester {
public static void nestJars(Collection<File> jars, File modJar, Logger logger) {
if (jars.isEmpty()) {
logger.debug("Nothing to nest into " + modJar.getName());
return;
}
Preconditions.checkArgument(ModUtils.isMod(modJar), "Cannot nest jars into none mod jar " + modJar.getName());
ZipUtil.addEntries(modJar, jars.stream().map(file -> new FileSource("META-INF/jars/" + file.getName(), file)).toArray(ZipEntrySource[]::new));
boolean didNest = ZipUtil.transformEntries(modJar, single(new ZipEntryTransformerEntry("fabric.mod.json", new StringZipEntryTransformer() {
@Override
protected String transform(ZipEntry zipEntry, String input) {
JsonObject json = LoomGradlePlugin.GSON.fromJson(input, JsonObject.class);
JsonArray nestedJars = json.getAsJsonArray("jars");
if (nestedJars == null || !json.has("jars")) {
nestedJars = new JsonArray();
}
for (File file : jars) {
String nestedJarPath = "META-INF/jars/" + file.getName();
for (JsonElement nestedJar : nestedJars) {
JsonObject jsonObject = nestedJar.getAsJsonObject();
if (jsonObject.has("file") && jsonObject.get("file").getAsString().equals(nestedJarPath)) {
throw new IllegalStateException("Cannot nest 2 jars at the same path: " + nestedJarPath);
}
}
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("file", nestedJarPath);
nestedJars.add(jsonObject);
logger.debug("Nested " + nestedJarPath + " into " + modJar.getName());
}
json.add("jars", nestedJars);
return LoomGradlePlugin.GSON.toJson(json);
}
})));
Preconditions.checkArgument(didNest, "Failed to nest jars into " + modJar.getName());
}
private static ZipEntryTransformerEntry[] single(ZipEntryTransformerEntry element) {
return new ZipEntryTransformerEntry[]{element};
}
}

View File

@ -0,0 +1,46 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016, 2017, 2018 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.build.nesting;
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
public class MergedNestedJarProvider implements NestedJarProvider {
private final NestedJarProvider[] parents;
public MergedNestedJarProvider(NestedJarProvider... parents) {
this.parents = parents;
}
@Override
public Collection<File> provide() {
return Arrays.stream(parents)
.map(NestedJarProvider::provide)
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
}

View File

@ -22,22 +22,18 @@
* SOFTWARE. * SOFTWARE.
*/ */
package net.fabricmc.loom.build; package net.fabricmc.loom.build.nesting;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.gradle.api.Project; import org.gradle.api.Project;
@ -50,121 +46,30 @@ import org.gradle.api.artifacts.ResolvedArtifact;
import org.gradle.api.artifacts.ResolvedConfiguration; import org.gradle.api.artifacts.ResolvedConfiguration;
import org.gradle.api.artifacts.ResolvedDependency; import org.gradle.api.artifacts.ResolvedDependency;
import org.gradle.api.tasks.bundling.AbstractArchiveTask; import org.gradle.api.tasks.bundling.AbstractArchiveTask;
import org.zeroturnaround.zip.FileSource;
import org.zeroturnaround.zip.ZipEntrySource;
import org.zeroturnaround.zip.ZipUtil; 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.LoomGradleExtension;
import net.fabricmc.loom.LoomGradlePlugin; import net.fabricmc.loom.LoomGradlePlugin;
import net.fabricmc.loom.task.RemapJarTask; import net.fabricmc.loom.task.RemapJarTask;
import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.Constants;
public class NestedJars { public final class NestedDependencyProvider implements NestedJarProvider {
public static boolean addNestedJars(Project project, Path modJarPath) { final Project project;
List<File> containedJars = getContainedJars(project); final List<DependencyInfo<?>> files;
if (containedJars.isEmpty()) { private NestedDependencyProvider(Project project, List<DependencyInfo<?>> files) {
return false; this.project = project;
this.files = files;
} }
File modJar = modJarPath.toFile(); public static NestedDependencyProvider createNestedDependencyProviderFromConfiguration(Project project, Configuration configuration) {
List<DependencyInfo<?>> fileList = new ArrayList<>();
Set<String> visited = new HashSet<>();
ZipUtil.addOrReplaceEntries(modJar, containedJars.stream().map(file -> new FileSource("META-INF/jars/" + file.getName(), file)).toArray(ZipEntrySource[]::new)); fileList.addAll(populateProjectDependencies(configuration, visited));
fileList.addAll(populateResolvedDependencies(configuration, visited));
return ZipUtil.transformEntries(modJar, single(new ZipEntryTransformerEntry("fabric.mod.json", new StringZipEntryTransformer() { return new NestedDependencyProvider(project, fileList);
@Override
protected String transform(ZipEntry zipEntry, String input) {
JsonObject json = LoomGradlePlugin.GSON.fromJson(input, JsonObject.class);
JsonArray nestedJars = json.getAsJsonArray("jars");
if (nestedJars == null || !json.has("jars")) {
nestedJars = new JsonArray();
}
for (File file : containedJars) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("file", "META-INF/jars/" + file.getName());
nestedJars.add(jsonObject);
}
json.add("jars", nestedJars);
return LoomGradlePlugin.GSON.toJson(json);
}
})));
}
private static List<File> getContainedJars(Project project) {
List<File> fileList = new ArrayList<>();
Configuration configuration = project.getConfigurations().getByName(Constants.Configurations.INCLUDE);
ResolvedConfiguration resolvedConfiguration = configuration.getResolvedConfiguration();
Set<ResolvedDependency> dependencies = resolvedConfiguration.getFirstLevelModuleDependencies();
// Bit ugly doing this, id guess there is a better way but this works.
Set<String> projectDeps = new HashSet<>();
for (Dependency dependency : configuration.getDependencies()) {
if (dependency instanceof ProjectDependency) {
ProjectDependency projectDependency = (ProjectDependency) dependency;
Project dependencyProject = projectDependency.getDependencyProject();
projectDeps.add(dependency.getGroup() + ":" + dependency.getName() + ":" + dependency.getVersion());
// TODO change this to allow just normal jar tasks, so a project can have a none loom sub project
Collection<Task> remapJarTasks = dependencyProject.getTasksByName("remapJar", false);
Collection<Task> jarTasks = dependencyProject.getTasksByName("jar", false);
for (Task task : remapJarTasks.isEmpty() ? jarTasks : remapJarTasks) {
if (task instanceof RemapJarTask) {
fileList.addAll(prepareForNesting(
Collections.singleton(((RemapJarTask) task).getArchivePath()),
projectDependency,
new ProjectDependencyMetaExtractor(),
project
));
} else if (task instanceof AbstractArchiveTask) {
fileList.addAll(prepareForNesting(
Collections.singleton(((AbstractArchiveTask) task).getArchivePath()),
projectDependency,
new ProjectDependencyMetaExtractor(),
project
));
}
}
}
}
for (ResolvedDependency dependency : dependencies) {
if (projectDeps.contains(dependency.getModuleGroup() + ":" + dependency.getModuleName() + ":" + dependency.getModuleVersion())) {
continue;
} else {
fileList.addAll(prepareForNesting(
dependency
.getModuleArtifacts()
.stream()
.map(ResolvedArtifact::getFile)
.collect(Collectors.toSet()),
dependency,
new ResolvedDependencyMetaExtractor(),
project
));
}
}
for (File file : fileList) {
if (!file.exists()) {
throw new RuntimeException("Failed to include nested jars, as it could not be found @ " + file.getAbsolutePath());
}
if (file.isDirectory() || !file.getName().endsWith(".jar")) {
throw new RuntimeException("Failed to include nested jars, as file was not a jar: " + file.getAbsolutePath());
}
}
return fileList;
} }
// Looks for any deps that require a sub project to be built first // Looks for any deps that require a sub project to be built first
@ -190,11 +95,69 @@ public class NestedJars {
return remapTasks; return remapTasks;
} }
//This is a good place to do pre-nesting operations, such as adding a fabric.mod.json to a library private static List<DependencyInfo<ProjectDependency>> populateProjectDependencies(Configuration configuration, Set<String> visited) {
private static <D> List<File> prepareForNesting(Set<File> files, D dependency, DependencyMetaExtractor<D> metaExtractor, Project project) { List<DependencyInfo<ProjectDependency>> fileList = new ArrayList<>();
List<File> fileList = new ArrayList<>();
for (Dependency dependency : configuration.getDependencies()) {
if (dependency instanceof ProjectDependency) {
ProjectDependency projectDependency = (ProjectDependency) dependency;
Project dependencyProject = projectDependency.getDependencyProject();
visited.add(dependency.getGroup() + ":" + dependency.getName() + ":" + dependency.getVersion());
// TODO change this to allow just normal jar tasks, so a project can have a none loom sub project
Collection<Task> remapJarTasks = dependencyProject.getTasksByName("remapJar", false);
Collection<Task> jarTasks = dependencyProject.getTasksByName("jar", false);
for (Task task : remapJarTasks.isEmpty() ? jarTasks : remapJarTasks) {
if (task instanceof RemapJarTask) {
File file = ((RemapJarTask) task).getArchivePath();
fileList.add(new DependencyInfo<>(projectDependency, new ProjectDependencyMetaExtractor(), file));
} else if (task instanceof AbstractArchiveTask) {
File file = ((AbstractArchiveTask) task).getArchivePath();
fileList.add(new DependencyInfo<>(projectDependency, new ProjectDependencyMetaExtractor(), file));
}
}
}
}
return fileList;
}
private static List<DependencyInfo<ResolvedDependency>> populateResolvedDependencies(Configuration configuration, Set<String> visited) {
ResolvedConfiguration resolvedConfiguration = configuration.getResolvedConfiguration();
Set<ResolvedDependency> dependencies = resolvedConfiguration.getFirstLevelModuleDependencies();
List<DependencyInfo<ResolvedDependency>> fileList = new ArrayList<>();
for (ResolvedDependency dependency : dependencies) {
if (visited.contains(dependency.getModuleGroup() + ":" + dependency.getModuleName() + ":" + dependency.getModuleVersion())) {
continue;
}
List<File> files = dependency
.getModuleArtifacts()
.stream()
.map(ResolvedArtifact::getFile)
.collect(Collectors.toList());
for (File file : files) { for (File file : files) {
fileList.add(new DependencyInfo<>(dependency, new ResolvedDependencyMetaExtractor(), file));
}
}
return fileList;
}
@Override
public List<File> provide() {
List<File> fileList = new ArrayList<>();
for (DependencyInfo<?> metaFile : files) {
metaFile.validateInputs();
File file = metaFile.file;
//A lib that doesnt have a mod.json, we turn it into a fake mod //A lib that doesnt have a mod.json, we turn it into a fake mod
if (!ZipUtil.containsEntry(file, "fabric.mod.json")) { if (!ZipUtil.containsEntry(file, "fabric.mod.json")) {
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
@ -216,7 +179,7 @@ public class NestedJars {
throw new RuntimeException("Failed to copy file", e); throw new RuntimeException("Failed to copy file", e);
} }
ZipUtil.addEntry(tempFile, "fabric.mod.json", getMod(dependency, metaExtractor).getBytes()); ZipUtil.addEntry(tempFile, "fabric.mod.json", generateModForDependency(metaFile).getBytes());
fileList.add(tempFile); fileList.add(tempFile);
} else { } else {
// Default copy the jar right in // Default copy the jar right in
@ -228,7 +191,10 @@ public class NestedJars {
} }
// Generates a barebones mod for a dependency // Generates a barebones mod for a dependency
private static <D> String getMod(D dependency, DependencyMetaExtractor<D> metaExtractor) { private static <D> String generateModForDependency(DependencyInfo<D> info) {
DependencyMetaExtractor<D> metaExtractor = info.metaExtractor;
D dependency = info.dependency;
JsonObject jsonObject = new JsonObject(); JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("schemaVersion", 1); jsonObject.addProperty("schemaVersion", 1);
jsonObject.addProperty("id", (metaExtractor.group(dependency) + "_" + metaExtractor.name(dependency)).replaceAll("\\.", "_").toLowerCase(Locale.ENGLISH)); jsonObject.addProperty("id", (metaExtractor.group(dependency) + "_" + metaExtractor.name(dependency)).replaceAll("\\.", "_").toLowerCase(Locale.ENGLISH));
@ -242,8 +208,26 @@ public class NestedJars {
return LoomGradlePlugin.GSON.toJson(jsonObject); return LoomGradlePlugin.GSON.toJson(jsonObject);
} }
private static ZipEntryTransformerEntry[] single(ZipEntryTransformerEntry element) { private static class DependencyInfo<D> {
return new ZipEntryTransformerEntry[]{element}; final D dependency;
final DependencyMetaExtractor<D> metaExtractor;
final File file;
DependencyInfo(D dependency, DependencyMetaExtractor<D> metaExtractor, File file) {
this.dependency = dependency;
this.metaExtractor = metaExtractor;
this.file = file;
}
public void validateInputs() {
if (!file.exists()) {
throw new RuntimeException("Failed to include nested jars, as it could not be found @ " + file.getAbsolutePath());
}
if (file.isDirectory() || !file.getName().endsWith(".jar")) {
throw new RuntimeException("Failed to include nested jars, as file was not a jar: " + file.getAbsolutePath());
}
}
} }
private interface DependencyMetaExtractor<D> { private interface DependencyMetaExtractor<D> {

View File

@ -0,0 +1,67 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016, 2017, 2018 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.build.nesting;
import java.io.File;
import java.util.Collection;
import java.util.Set;
import com.google.common.base.Preconditions;
import org.gradle.api.Project;
import net.fabricmc.loom.util.ModUtils;
public final class NestedJarPathProvider implements NestedJarProvider {
private final Set<Object> nestedPaths;
private Set<File> files = null;
public NestedJarPathProvider(Set<Object> nestedPaths) {
this.nestedPaths = nestedPaths;
}
private Set<File> resolve(Project project) {
return project.files(nestedPaths).getFiles();
}
@Override
public void prepare(Project project) {
if (files == null) {
files = resolve(project);
}
}
@Override
public Collection<File> provide() {
validateFiles();
return files;
}
private void validateFiles() {
for (File file : files) {
Preconditions.checkArgument(file.getName().endsWith(".jar"), String.format("Tried to nest %s but it is not a jar", file.getAbsolutePath()));
Preconditions.checkArgument(file.exists(), String.format("Tried to nest jar %s but it does not exist", file.getAbsolutePath()));
Preconditions.checkArgument(ModUtils.isMod(file), String.format("Cannot use nest none mod jar %s", file.getAbsolutePath()));
}
}
}

View File

@ -0,0 +1,40 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016, 2017, 2018 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.build.nesting;
import java.io.File;
import java.util.Collection;
import org.gradle.api.Project;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
public interface NestedJarProvider {
// provide all the files to be included, they should already be resolved but can be transformed here
Collection<File> provide();
// Setup the files ready to be provided
default void prepare(Project project) { }
}

View File

@ -24,13 +24,8 @@
package net.fabricmc.loom.configuration; package net.fabricmc.loom.configuration;
import java.io.IOException;
import org.gradle.api.Project; 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.artifacts.Configuration;
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSet;
@ -38,8 +33,6 @@ import org.gradle.api.tasks.bundling.AbstractArchiveTask;
import org.gradle.api.tasks.javadoc.Javadoc; import org.gradle.api.tasks.javadoc.Javadoc;
import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.build.JarRemapper;
import net.fabricmc.loom.build.NestedJars;
import net.fabricmc.loom.build.mixin.JavaApInvoker; import net.fabricmc.loom.build.mixin.JavaApInvoker;
import net.fabricmc.loom.build.mixin.KaptApInvoker; import net.fabricmc.loom.build.mixin.KaptApInvoker;
import net.fabricmc.loom.build.mixin.ScalaApInvoker; import net.fabricmc.loom.build.mixin.ScalaApInvoker;
@ -47,16 +40,8 @@ import net.fabricmc.loom.configuration.ide.SetupIntelijRunConfigs;
import net.fabricmc.loom.configuration.providers.LaunchProvider; import net.fabricmc.loom.configuration.providers.LaunchProvider;
import net.fabricmc.loom.configuration.providers.MinecraftProvider; import net.fabricmc.loom.configuration.providers.MinecraftProvider;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider;
import net.fabricmc.loom.task.AbstractLoomTask;
import net.fabricmc.loom.task.RemapAllSourcesTask;
import net.fabricmc.loom.task.RemapJarTask;
import net.fabricmc.loom.task.RemapSourcesJarTask;
import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.SourceRemapper;
/**
* Add Minecraft dependencies to compile time.
*/
public final class CompileConfiguration { public final class CompileConfiguration {
private CompileConfiguration() { private CompileConfiguration() {
} }
@ -110,53 +95,18 @@ public final class CompileConfiguration {
extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, project); extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, project);
} }
/** public static void configureCompile(Project p) {
* Permit to add a Maven repository to a target project. JavaPluginConvention javaModule = (JavaPluginConvention) p.getConvention().getPlugins().get("java");
*
* @param target The target project
* @param name The name of the repository
* @param url The URL of the repository
* @return An object containing the name and the URL of the repository that can be modified later
*/
public static MavenArtifactRepository addMavenRepo(Project target, final String name, final String url) {
return target.getRepositories().maven(repo -> {
repo.setName(name);
repo.setUrl(url);
});
}
public static void configureCompile(Project project) {
JavaPluginConvention javaModule = (JavaPluginConvention) project.getConvention().getPlugins().get("java");
SourceSet main = javaModule.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME); SourceSet main = javaModule.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME);
Javadoc javadoc = (Javadoc) project.getTasks().getByName(JavaPlugin.JAVADOC_TASK_NAME); Javadoc javadoc = (Javadoc) p.getTasks().getByName(JavaPlugin.JAVADOC_TASK_NAME);
javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath())); javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath()));
project.afterEvaluate(project1 -> { p.afterEvaluate(project -> {
LoomGradleExtension extension = project1.getExtensions().getByType(LoomGradleExtension.class); LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
project1.getRepositories().flatDir(flatDirectoryArtifactRepository -> { MavenConfiguration.setup(project);
flatDirectoryArtifactRepository.dir(extension.getRootProjectBuildCache());
flatDirectoryArtifactRepository.setName("UserLocalCacheFiles");
});
project1.getRepositories().maven(mavenArtifactRepository -> {
mavenArtifactRepository.setUrl(extension.getRemappedModCache());
mavenArtifactRepository.setName("UserLocalRemappedMods");
});
project1.getRepositories().maven(mavenArtifactRepository -> {
mavenArtifactRepository.setName("Fabric");
mavenArtifactRepository.setUrl("https://maven.fabricmc.net/");
});
project1.getRepositories().maven(mavenArtifactRepository -> {
mavenArtifactRepository.setName("Mojang");
mavenArtifactRepository.setUrl("https://libraries.minecraft.net/");
});
project1.getRepositories().mavenCentral();
LoomDependencyManager dependencyManager = new LoomDependencyManager(); LoomDependencyManager dependencyManager = new LoomDependencyManager();
extension.setDependencyManager(dependencyManager); extension.setDependencyManager(dependencyManager);
@ -165,100 +115,19 @@ public final class CompileConfiguration {
dependencyManager.addProvider(new MappingsProvider(project)); dependencyManager.addProvider(new MappingsProvider(project));
dependencyManager.addProvider(new LaunchProvider(project)); dependencyManager.addProvider(new LaunchProvider(project));
dependencyManager.handleDependencies(project1); dependencyManager.handleDependencies(project);
project1.getTasks().getByName("idea").finalizedBy(project1.getTasks().getByName("genIdeaWorkspace")); project.getTasks().getByName("idea").finalizedBy(project.getTasks().getByName("genIdeaWorkspace"));
project1.getTasks().getByName("eclipse").finalizedBy(project1.getTasks().getByName("genEclipseRuns")); project.getTasks().getByName("eclipse").finalizedBy(project.getTasks().getByName("genEclipseRuns"));
project1.getTasks().getByName("cleanEclipse").finalizedBy(project1.getTasks().getByName("cleanEclipseRuns")); project.getTasks().getByName("cleanEclipse").finalizedBy(project.getTasks().getByName("cleanEclipseRuns"));
SetupIntelijRunConfigs.setup(project1); SetupIntelijRunConfigs.setup(project);
// Enables the default mod remapper // Enables the default mod remapper
if (extension.remapMod) { if (extension.remapMod) {
AbstractArchiveTask jarTask = (AbstractArchiveTask) project1.getTasks().getByName("jar"); RemapConfiguration.setupDefaultRemap(project);
RemapJarTask remapJarTask = (RemapJarTask) project1.getTasks().findByName("remapJar");
assert remapJarTask != null;
if (!remapJarTask.getInput().isPresent()) {
jarTask.setClassifier("dev");
remapJarTask.setClassifier("");
remapJarTask.getInput().set(jarTask.getArchivePath());
}
extension.getUnmappedModCollection().from(jarTask);
remapJarTask.getAddNestedDependencies().set(true);
remapJarTask.getRemapAccessWidener().set(true);
project1.getArtifacts().add("archives", remapJarTask);
remapJarTask.dependsOn(jarTask);
project1.getTasks().getByName("build").dependsOn(remapJarTask);
project.getTasks().withType(RemapJarTask.class).forEach(task -> {
if (task.getAddNestedDependencies().getOrElse(false)) {
NestedJars.getRequiredTasks(project1).forEach(task::dependsOn);
}
});
SourceRemapper remapper = null;
Task parentTask = project1.getTasks().getByName("build");
if (extension.isShareCaches()) {
Project rootProject = project.getRootProject();
if (extension.isRootProject()) {
SourceRemapper sourceRemapper = new SourceRemapper(rootProject, false);
JarRemapper jarRemapper = new JarRemapper();
remapJarTask.jarRemapper = jarRemapper;
rootProject.getTasks().register("remapAllSources", RemapAllSourcesTask.class, task -> {
task.sourceRemapper = sourceRemapper;
task.doLast(t -> sourceRemapper.remapAll());
});
parentTask = rootProject.getTasks().getByName("remapAllSources");
rootProject.getTasks().register("remapAllJars", AbstractLoomTask.class, task -> {
task.doLast(t -> {
try {
jarRemapper.remap();
} catch (IOException e) {
throw new RuntimeException("Failed to remap jars", e);
}
});
});
} else { } else {
parentTask = rootProject.getTasks().getByName("remapAllSources"); AbstractArchiveTask jarTask = (AbstractArchiveTask) project.getTasks().getByName("jar");
remapper = ((RemapAllSourcesTask) parentTask).sourceRemapper;
remapJarTask.jarRemapper = ((RemapJarTask) rootProject.getTasks().getByName("remapJar")).jarRemapper;
project1.getTasks().getByName("build").dependsOn(parentTask);
project1.getTasks().getByName("build").dependsOn(rootProject.getTasks().getByName("remapAllJars"));
rootProject.getTasks().getByName("remapAllJars").dependsOn(project1.getTasks().getByName("remapJar"));
}
}
try {
AbstractArchiveTask sourcesTask = (AbstractArchiveTask) project1.getTasks().getByName("sourcesJar");
RemapSourcesJarTask remapSourcesJarTask = (RemapSourcesJarTask) project1.getTasks().findByName("remapSourcesJar");
remapSourcesJarTask.setInput(sourcesTask.getArchivePath());
remapSourcesJarTask.setOutput(sourcesTask.getArchivePath());
remapSourcesJarTask.doLast(task -> project1.getArtifacts().add("archives", remapSourcesJarTask.getOutput()));
remapSourcesJarTask.dependsOn(project1.getTasks().getByName("sourcesJar"));
if (extension.isShareCaches()) {
remapSourcesJarTask.setSourceRemapper(remapper);
}
parentTask.dependsOn(remapSourcesJarTask);
} catch (UnknownTaskException ignored) {
// pass
}
} else {
AbstractArchiveTask jarTask = (AbstractArchiveTask) project1.getTasks().getByName("jar");
extension.getUnmappedModCollection().from(jarTask); extension.getUnmappedModCollection().from(jarTask);
} }
@ -281,7 +150,7 @@ public final class CompileConfiguration {
} }
}); });
if (project.getPluginManager().hasPlugin("org.jetbrains.kotlin.kapt")) { if (p.getPluginManager().hasPlugin("org.jetbrains.kotlin.kapt")) {
// If loom is applied after kapt, then kapt will use the AP arguments too early for loom to pass the arguments we need for mixin. // If loom is applied after kapt, then kapt will use the AP arguments too early for loom to pass the arguments we need for mixin.
throw new IllegalArgumentException("fabric-loom must be applied BEFORE kapt in the plugins { } block."); throw new IllegalArgumentException("fabric-loom must be applied BEFORE kapt in the plugins { } block.");
} }

View File

@ -0,0 +1,57 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016, 2017, 2018 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;
import org.gradle.api.Project;
import net.fabricmc.loom.LoomGradleExtension;
public class MavenConfiguration {
public static void setup(Project project) {
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
project.getRepositories().flatDir(repo -> {
repo.setName("UserLocalCacheFiles");
repo.dir(extension.getRootProjectBuildCache());
});
project.getRepositories().maven(repo -> {
repo.setName("UserLocalRemappedMods");
repo.setUrl(extension.getRemappedModCache());
});
project.getRepositories().maven(repo -> {
repo.setName("Fabric");
repo.setUrl("https://maven.fabricmc.net/");
});
project.getRepositories().maven(repo -> {
repo.setName("Mojang");
repo.setUrl("https://libraries.minecraft.net/");
});
project.getRepositories().mavenCentral();
}
}

View File

@ -0,0 +1,159 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016, 2017, 2018 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;
import java.io.IOException;
import com.google.common.base.Preconditions;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.UnknownTaskException;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.tasks.bundling.AbstractArchiveTask;
import org.jetbrains.annotations.ApiStatus;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.build.JarRemapper;
import net.fabricmc.loom.build.nesting.NestedDependencyProvider;
import net.fabricmc.loom.task.AbstractLoomTask;
import net.fabricmc.loom.task.RemapAllSourcesTask;
import net.fabricmc.loom.task.RemapJarTask;
import net.fabricmc.loom.task.RemapSourcesJarTask;
import net.fabricmc.loom.util.SourceRemapper;
public class RemapConfiguration {
private static final String DEFAULT_JAR_TASK_NAME = JavaPlugin.JAR_TASK_NAME;
private static final String DEFAULT_SOURCES_JAR_TASK_NAME = "sourcesJar";
private static final String DEFAULT_REMAP_JAR_TASK_NAME = "remapJar";
private static final String DEFAULT_REMAP_SOURCES_JAR_TASK_NAME = "remapSourcesJar";
private static final String DEFAULT_REMAP_ALL_JARS_TASK_NAME = "remapAllJars";
private static final String DEFAULT_REMAP_ALL_SOURCES_TASK_NAME = "remapAllSources";
public static void setupDefaultRemap(Project project) {
setupRemap(project, true, DEFAULT_JAR_TASK_NAME, DEFAULT_SOURCES_JAR_TASK_NAME, DEFAULT_REMAP_JAR_TASK_NAME, DEFAULT_REMAP_SOURCES_JAR_TASK_NAME, DEFAULT_REMAP_ALL_JARS_TASK_NAME, DEFAULT_REMAP_ALL_SOURCES_TASK_NAME);
}
@ApiStatus.Experimental // This is only an api if you squint really hard, expect it to explode every 5 mins. If you must call in afterEvaluate on all projects
public static void setupRemap(Project project, String jarTaskName, String sourcesJarTaskName, String remapJarTaskName, String remapSourcesJarTaskName, String remapAllJarsTaskName, String remapAllSourcesTaskName) {
setupRemap(project, false, jarTaskName, sourcesJarTaskName, remapJarTaskName, remapSourcesJarTaskName, remapAllJarsTaskName, remapAllSourcesTaskName);
}
// isDefaultRemap is set to true for the standard remap task, some defaults are left out when this is false.
private static void setupRemap(Project project, boolean isDefaultRemap, String jarTaskName, String sourcesJarTaskName, String remapJarTaskName, String remapSourcesJarTaskName, String remapAllJarsTaskName, String remapAllSourcesTaskName) {
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
AbstractArchiveTask jarTask = (AbstractArchiveTask) project.getTasks().getByName(jarTaskName);
RemapJarTask remapJarTask = (RemapJarTask) project.getTasks().findByName(remapJarTaskName);
assert remapJarTask != null;
if (!remapJarTask.getInput().isPresent() && isDefaultRemap) {
jarTask.setClassifier("dev");
remapJarTask.setClassifier("");
remapJarTask.getInput().set(jarTask.getArchivePath());
}
if (isDefaultRemap) {
extension.getUnmappedModCollection().from(jarTask);
remapJarTask.getAddNestedDependencies().set(true);
remapJarTask.getRemapAccessWidener().set(true);
project.getArtifacts().add("archives", remapJarTask);
}
remapJarTask.dependsOn(jarTask);
project.getTasks().getByName("build").dependsOn(remapJarTask);
// TODO this might be wrong?
project.getTasks().withType(RemapJarTask.class).forEach(task -> {
if (task.getAddNestedDependencies().getOrElse(false)) {
NestedDependencyProvider.getRequiredTasks(project).forEach(task::dependsOn);
}
});
SourceRemapper remapper = null;
// TODO what is this for?
Task parentTask = project.getTasks().getByName("build");
if (extension.isShareCaches()) {
Project rootProject = project.getRootProject();
if (extension.isRootProject()) {
SourceRemapper sourceRemapper = new SourceRemapper(rootProject, false);
JarRemapper jarRemapper = new JarRemapper();
remapJarTask.jarRemapper = jarRemapper;
rootProject.getTasks().register(remapAllSourcesTaskName, RemapAllSourcesTask.class, task -> {
task.sourceRemapper = sourceRemapper;
task.doLast(t -> sourceRemapper.remapAll());
});
parentTask = rootProject.getTasks().getByName(remapAllSourcesTaskName);
rootProject.getTasks().register(remapAllJarsTaskName, AbstractLoomTask.class, task -> {
task.doLast(t -> {
try {
jarRemapper.remap();
} catch (IOException e) {
throw new RuntimeException("Failed to remap jars", e);
}
});
});
} else {
parentTask = rootProject.getTasks().getByName(remapAllSourcesTaskName);
remapper = ((RemapAllSourcesTask) parentTask).sourceRemapper;
Preconditions.checkNotNull(remapper);
remapJarTask.jarRemapper = ((RemapJarTask) rootProject.getTasks().getByName(remapJarTaskName)).jarRemapper;
project.getTasks().getByName("build").dependsOn(parentTask);
project.getTasks().getByName("build").dependsOn(rootProject.getTasks().getByName(remapAllJarsTaskName));
rootProject.getTasks().getByName(remapAllJarsTaskName).dependsOn(project.getTasks().getByName(remapJarTaskName));
}
}
try {
AbstractArchiveTask sourcesTask = (AbstractArchiveTask) project.getTasks().getByName(sourcesJarTaskName);
RemapSourcesJarTask remapSourcesJarTask = (RemapSourcesJarTask) project.getTasks().findByName(remapSourcesJarTaskName);
Preconditions.checkNotNull(remapSourcesJarTask, "Could not find " + remapSourcesJarTaskName + " in " + project.getName());
remapSourcesJarTask.setInput(sourcesTask.getArchivePath());
remapSourcesJarTask.setOutput(sourcesTask.getArchivePath());
remapSourcesJarTask.dependsOn(project.getTasks().getByName(sourcesJarTaskName));
if (isDefaultRemap) {
remapSourcesJarTask.doLast(task -> project.getArtifacts().add("archives", remapSourcesJarTask.getOutput()));
}
if (extension.isShareCaches()) {
remapSourcesJarTask.setSourceRemapper(remapper);
}
parentTask.dependsOn(remapSourcesJarTask);
} catch (UnknownTaskException ignored) {
// pass
}
}
}

View File

@ -30,11 +30,15 @@ import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import org.gradle.api.Action; import org.gradle.api.Action;
import org.gradle.api.Project; import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileCollection;
import org.gradle.api.file.RegularFileProperty; import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property; import org.gradle.api.provider.Property;
@ -42,49 +46,64 @@ import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile; import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.TaskAction;
import org.gradle.jvm.tasks.Jar; import org.gradle.jvm.tasks.Jar;
import org.jetbrains.annotations.ApiStatus;
import org.zeroturnaround.zip.ZipUtil; import org.zeroturnaround.zip.ZipUtil;
import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.build.JarRemapper; import net.fabricmc.loom.build.JarRemapper;
import net.fabricmc.loom.build.MixinRefmapHelper; import net.fabricmc.loom.build.MixinRefmapHelper;
import net.fabricmc.loom.build.NestedJars; import net.fabricmc.loom.build.nesting.NestedJarPathProvider;
import net.fabricmc.loom.build.nesting.JarNester;
import net.fabricmc.loom.build.nesting.MergedNestedJarProvider;
import net.fabricmc.loom.build.nesting.NestedDependencyProvider;
import net.fabricmc.loom.build.nesting.NestedJarProvider;
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor; import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.TinyRemapperMappingsHelper; import net.fabricmc.loom.util.TinyRemapperMappingsHelper;
import net.fabricmc.loom.util.ZipReprocessorUtil;
import net.fabricmc.loom.util.gradle.GradleSupport; import net.fabricmc.loom.util.gradle.GradleSupport;
import net.fabricmc.stitch.util.Pair; import net.fabricmc.stitch.util.Pair;
import net.fabricmc.tinyremapper.OutputConsumerPath;
import net.fabricmc.tinyremapper.TinyRemapper; import net.fabricmc.tinyremapper.TinyRemapper;
import net.fabricmc.tinyremapper.TinyUtils; import net.fabricmc.tinyremapper.TinyUtils;
public class RemapJarTask extends Jar { public class RemapJarTask extends Jar {
private final RegularFileProperty input; private final RegularFileProperty input;
private final Property<Boolean> addNestedDependencies; private final Property<Boolean> addNestedDependencies;
private final Property<Boolean> addDefaultNestedDependencies;
private final Property<Boolean> remapAccessWidener; private final Property<Boolean> remapAccessWidener;
private final List<Action<TinyRemapper.Builder>> remapOptions = new ArrayList<>(); private final List<Action<TinyRemapper.Builder>> remapOptions = new ArrayList<>();
public JarRemapper jarRemapper; public JarRemapper jarRemapper;
private FileCollection classpath; private FileCollection classpath;
private final Set<Object> nestedPaths = new LinkedHashSet<>();
public RemapJarTask() { public RemapJarTask() {
super(); super();
input = GradleSupport.getfileProperty(getProject()); input = GradleSupport.getfileProperty(getProject());
addNestedDependencies = getProject().getObjects().property(Boolean.class); addNestedDependencies = getProject().getObjects().property(Boolean.class);
addDefaultNestedDependencies = getProject().getObjects().property(Boolean.class);
remapAccessWidener = getProject().getObjects().property(Boolean.class); remapAccessWidener = getProject().getObjects().property(Boolean.class);
// false by default, I have no idea why I have to do it for this property and not the other one // false by default, I have no idea why I have to do it for this property and not the other one
remapAccessWidener.set(false); remapAccessWidener.set(false);
addDefaultNestedDependencies.set(true);
} }
@TaskAction @TaskAction
public void doTask() throws Throwable { public void doTask() throws Throwable {
boolean singleRemap = false;
if (jarRemapper == null) { if (jarRemapper == null) {
doSingleRemap(); singleRemap = true;
} else { jarRemapper = new JarRemapper();
scheduleRemap(); }
scheduleRemap(singleRemap || getProject().getExtensions().getByType(LoomGradleExtension.class).isRootProject());
if (singleRemap) {
jarRemapper.remap();
} }
} }
public void doSingleRemap() throws Throwable { public void scheduleRemap(boolean isMainRemapTask) throws Throwable {
Project project = getProject(); Project project = getProject();
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
Path input = this.getInput().getAsFile().get().toPath(); Path input = this.getInput().getAsFile().get().toPath();
@ -99,86 +118,7 @@ public class RemapJarTask extends Jar {
String fromM = "named"; String fromM = "named";
String toM = "intermediary"; String toM = "intermediary";
Path[] classpath = getRemapClasspath(); if (isMainRemapTask) {
TinyRemapper.Builder remapperBuilder = TinyRemapper.newRemapper();
remapperBuilder = remapperBuilder.withMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM, false));
for (File mixinMapFile : extension.getAllMixinMappings()) {
if (mixinMapFile.exists()) {
remapperBuilder = remapperBuilder.withMappings(TinyUtils.createTinyMappingProvider(mixinMapFile.toPath(), fromM, toM));
}
}
// Apply any requested options to tiny remapper
for (Action<TinyRemapper.Builder> remapOption : this.remapOptions) {
remapOption.execute(remapperBuilder);
}
project.getLogger().info(":remapping " + input.getFileName());
StringBuilder rc = new StringBuilder("Remap classpath: ");
for (Path p : classpath) {
rc.append("\n - ").append(p.toString());
}
project.getLogger().debug(rc.toString());
TinyRemapper remapper = remapperBuilder.build();
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(output).build()) {
outputConsumer.addNonClassFiles(input);
remapper.readClassPath(classpath);
remapper.readInputs(input);
remapper.apply(outputConsumer);
} catch (Exception e) {
remapper.finish();
throw new RuntimeException("Failed to remap " + input + " to " + output, e);
}
if (getRemapAccessWidener().getOrElse(false) && extension.accessWidener != null) {
extension.getJarProcessorManager().getByType(AccessWidenerJarProcessor.class).remapAccessWidener(output, remapper.getRemapper());
}
remapper.finish();
if (!Files.exists(output)) {
throw new RuntimeException("Failed to remap " + input + " to " + output + " - file missing!");
}
if (MixinRefmapHelper.addRefmapName(extension.getRefmapName(), output)) {
project.getLogger().debug("Transformed mixin reference maps in output JAR!");
}
if (getAddNestedDependencies().getOrElse(false)) {
if (NestedJars.addNestedJars(project, output)) {
project.getLogger().debug("Added nested jar paths to mod json");
}
}
if (isReproducibleFileOrder() || isPreserveFileTimestamps()) {
ZipReprocessorUtil.reprocessZip(output.toFile(), isReproducibleFileOrder(), isPreserveFileTimestamps());
}
}
public void scheduleRemap() throws Throwable {
Project project = getProject();
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
Path input = this.getInput().getAsFile().get().toPath();
Path output = this.getArchivePath().toPath();
if (!Files.exists(input)) {
throw new FileNotFoundException(input.toString());
}
MappingsProvider mappingsProvider = extension.getMappingsProvider();
String fromM = "named";
String toM = "intermediary";
if (extension.isRootProject()) {
jarRemapper.addToClasspath(getRemapClasspath()); jarRemapper.addToClasspath(getRemapClasspath());
jarRemapper.addMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM, false)); jarRemapper.addMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM, false));
@ -193,6 +133,9 @@ public class RemapJarTask extends Jar {
// Add remap options to the jar remapper // Add remap options to the jar remapper
jarRemapper.addOptions(this.remapOptions); jarRemapper.addOptions(this.remapOptions);
NestedJarProvider nestedJarProvider = getNestedJarProvider();
nestedJarProvider.prepare(getProject());
jarRemapper.scheduleRemap(input, output) jarRemapper.scheduleRemap(input, output)
.supplyAccessWidener((remapData, remapper) -> { .supplyAccessWidener((remapData, remapper) -> {
if (getRemapAccessWidener().getOrElse(false) && extension.accessWidener != null) { if (getRemapAccessWidener().getOrElse(false) && extension.accessWidener != null) {
@ -223,9 +166,7 @@ public class RemapJarTask extends Jar {
} }
if (getAddNestedDependencies().getOrElse(false)) { if (getAddNestedDependencies().getOrElse(false)) {
if (NestedJars.addNestedJars(project, output)) { JarNester.nestJars(nestedJarProvider.provide(), output.toFile(), project.getLogger());
project.getLogger().debug("Added nested jar paths to mod json");
}
} }
if (accessWidener != null) { if (accessWidener != null) {
@ -235,6 +176,25 @@ public class RemapJarTask extends Jar {
}); });
} }
private NestedJarProvider getNestedJarProvider() {
Configuration includeConfiguration = getProject().getConfigurations().getByName(Constants.Configurations.INCLUDE);
if (!addDefaultNestedDependencies.getOrElse(true)) {
return new NestedJarPathProvider(nestedPaths);
}
NestedJarProvider baseProvider = NestedDependencyProvider.createNestedDependencyProviderFromConfiguration(getProject(), includeConfiguration);
if (nestedPaths.isEmpty()) {
return baseProvider;
}
return new MergedNestedJarProvider(
baseProvider,
new NestedJarPathProvider(nestedPaths)
);
}
private Path[] getRemapClasspath() { private Path[] getRemapClasspath() {
FileCollection files = this.classpath; FileCollection files = this.classpath;
@ -258,6 +218,11 @@ public class RemapJarTask extends Jar {
return addNestedDependencies; return addNestedDependencies;
} }
@Input
public Property<Boolean> getAddDefaultNestedDependencies() {
return addDefaultNestedDependencies;
}
@Input @Input
public Property<Boolean> getRemapAccessWidener() { public Property<Boolean> getRemapAccessWidener() {
return remapAccessWidener; return remapAccessWidener;
@ -276,4 +241,12 @@ public class RemapJarTask extends Jar {
return this; return this;
} }
@ApiStatus.Experimental // This only allows mod jars, proceed with care when trying to pass in configurations with projects, or something that depends on a task.
public RemapJarTask include(Object... paths) {
Collections.addAll(nestedPaths, paths);
this.addNestedDependencies.set(true);
return this;
}
} }

View File

@ -0,0 +1,42 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016, 2017, 2018 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;
import java.io.File;
import java.io.IOException;
import java.util.zip.ZipFile;
public final class ModUtils {
private ModUtils() {
}
public static boolean isMod(File input) {
try (ZipFile zipFile = new ZipFile(input)) {
return zipFile.getEntry("fabric.mod.json") != null;
} catch (IOException e) {
return false;
}
}
}

View File

@ -58,9 +58,4 @@ class MultiProjectTest extends Specification implements ProjectTestTrait, Archiv
'6.8.3' | _ '6.8.3' | _
'7.0-milestone-2' | _ '7.0-milestone-2' | _
} }
@Override
String warningMode(String gradleVersion) {
"none" // TODO fix this!
}
} }

View File

@ -88,7 +88,7 @@ trait ProjectTestTrait {
return "all" return "all"
} }
System.getenv().TEST_WARNING_MODE ?: 'all' 'fail'
} }
String gradleHomeDirectory(String gradleVersion) { String gradleHomeDirectory(String gradleVersion) {

View File

@ -0,0 +1,6 @@
{
"schemaVersion": 1,
"id": "modid",
"version": "1.0.0",
"name": "Example Mod"
}