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 // Force add Mojang repository
addMavenRepo(target, "Mojang", "https://libraries.minecraft.net/"); addMavenRepo(target, "Mojang", "https://libraries.minecraft.net/");
Configuration compileModsConfig = project.getConfigurations().maybeCreate(Constants.COMPILE_MODS); Configuration modCompileClasspathConfig = project.getConfigurations().maybeCreate(Constants.MOD_COMPILE_CLASSPATH);
compileModsConfig.setTransitive(true); modCompileClasspathConfig.setTransitive(true);
Configuration compileModsMappedConfig = project.getConfigurations().maybeCreate(Constants.COMPILE_MODS_MAPPED); Configuration modCompileClasspathMappedConfig = project.getConfigurations().maybeCreate(Constants.MOD_COMPILE_CLASSPATH_MAPPED);
compileModsMappedConfig.setTransitive(false); // Don't get transitive deps of already remapped mods modCompileClasspathMappedConfig.setTransitive(false);
Configuration minecraftNamedConfig = project.getConfigurations().maybeCreate(Constants.MINECRAFT_NAMED); Configuration minecraftNamedConfig = project.getConfigurations().maybeCreate(Constants.MINECRAFT_NAMED);
minecraftNamedConfig.setTransitive(false); // The launchers do not recurse dependencies minecraftNamedConfig.setTransitive(false); // The launchers do not recurse dependencies
Configuration minecraftIntermediaryConfig = project.getConfigurations().maybeCreate(Constants.MINECRAFT_INTERMEDIARY); Configuration minecraftIntermediaryConfig = project.getConfigurations().maybeCreate(Constants.MINECRAFT_INTERMEDIARY);
@ -100,18 +101,32 @@ public class AbstractPlugin implements Plugin<Project> {
project.getConfigurations().maybeCreate(Constants.MAPPINGS); project.getConfigurations().maybeCreate(Constants.MAPPINGS);
configureIDEs(); for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) {
configureCompile(); 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_NAMED, Constants.MINECRAFT_DEPENDENCIES);
extendsFrom(Constants.MINECRAFT_INTERMEDIARY, 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("compile", Constants.MAPPINGS);
extendsFrom("annotationProcessor", Constants.COMPILE_MODS_MAPPED);
extendsFrom("annotationProcessor", Constants.MAPPINGS); extendsFrom("annotationProcessor", Constants.MAPPINGS);
configureIDEs();
configureCompile();
Map<Project, Set<Task>> taskMap = project.getAllTasks(true); Map<Project, Set<Task>> taskMap = project.getAllTasks(true);
for (Map.Entry<Project, Set<Task>> entry : taskMap.entrySet()) { for (Map.Entry<Project, Set<Task>> entry : taskMap.entrySet()) {
Project project = entry.getKey(); Project project = entry.getKey();
@ -331,7 +346,12 @@ public class AbstractPlugin implements Plugin<Project> {
protected void configureMaven() { protected void configureMaven() {
project.afterEvaluate((p) -> { project.afterEvaluate((p) -> {
Configuration compileModsConfig = p.getConfigurations().getByName(Constants.COMPILE_MODS); for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) {
if (!entry.hasMavenScope()) {
continue;
}
Configuration compileModsConfig = p.getConfigurations().getByName(entry.getSourceConfiguration());
// add modsCompile to maven-publish // add modsCompile to maven-publish
PublishingExtension mavenPublish = p.getExtensions().findByType(PublishingExtension.class); PublishingExtension mavenPublish = p.getExtensions().findByType(PublishingExtension.class);
@ -363,7 +383,7 @@ public class AbstractPlugin implements Plugin<Project> {
depNode.appendNode("groupId", dependency.getGroup()); depNode.appendNode("groupId", dependency.getGroup());
depNode.appendNode("artifactId", dependency.getName()); depNode.appendNode("artifactId", dependency.getName());
depNode.appendNode("version", dependency.getVersion()); depNode.appendNode("version", dependency.getVersion());
depNode.appendNode("scope", "compile"); depNode.appendNode("scope", entry.getMavenScope());
} }
}); });
}); });
@ -371,6 +391,7 @@ public class AbstractPlugin implements Plugin<Project> {
} }
}); });
} }
}
}); });
} }

View File

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

View File

@ -107,7 +107,7 @@ public class MigrateMappingsTask extends AbstractLoomTask {
mercury.getClassPath().add(file.toPath()); 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()); mercury.getClassPath().add(file.toPath());
} }

View File

@ -25,6 +25,10 @@
package net.fabricmc.loom.util; package net.fabricmc.loom.util;
import com.google.common.collect.ImmutableList;
import java.util.List;
public class Constants { public class Constants {
public static final String DEFAULT_FABRIC_CLIENT_TWEAKER = "net.fabricmc.loader.launch.FabricClientTweaker"; 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 SYSTEM_ARCH = System.getProperty("os.arch").equals("64") ? "64" : "32";
public static final String COMPILE_MODS = "modCompile"; public static final String MOD_COMPILE_CLASSPATH = "modCompileClasspath";
public static final String COMPILE_MODS_MAPPED = "modCompileMapped"; 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 INCLUDE = "include";
public static final String MINECRAFT = "minecraft"; public static final String MINECRAFT = "minecraft";
public static final String MINECRAFT_DEPENDENCIES = "minecraftLibraries"; public static final String MINECRAFT_DEPENDENCIES = "minecraftLibraries";

View File

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

View File

@ -82,7 +82,7 @@ public class ModCompileRemapper {
File modStore = extension.getRemappedModCache(); File modStore = extension.getRemappedModCache();
remapArtifact(project, artifact, remappedFilename, modStore); remapArtifact(project, modCompileRemapped, artifact, remappedFilename, modStore);
project.getDependencies().add(modCompileRemapped.getName(), project.getDependencies().module(remappedNotation)); project.getDependencies().add(modCompileRemapped.getName(), project.getDependencies().module(remappedNotation));
@ -118,13 +118,13 @@ public class ModCompileRemapper {
dependencies.add(regularCompile.getName(), dep); 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 input = artifact.getFile();
File output = new File(modStore, remappedFilename + ".jar"); File output = new File(modStore, remappedFilename + ".jar");
if (!output.exists() || input.lastModified() <= 0 || input.lastModified() > output.lastModified()) { 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 //If the output doesn't exist, or appears to be outdated compared to the input we'll remap it
try { try {
ModProcessor.handleMod(input, output, project); ModProcessor.processMod(input, output, project, config);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Failed to remap mod", e); throw new RuntimeException("Failed to remap mod", e);
} }
@ -137,6 +137,8 @@ public class ModCompileRemapper {
} else { } else {
project.getLogger().info(output.getName() + " is up to date with " + input.getName()); 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) { 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.loom.providers.MinecraftMappedProvider;
import net.fabricmc.tinyremapper.OutputConsumerPath; import net.fabricmc.tinyremapper.OutputConsumerPath;
import net.fabricmc.tinyremapper.TinyRemapper; import net.fabricmc.tinyremapper.TinyRemapper;
import net.fabricmc.tinyremapper.TinyUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.gradle.api.Project; import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.internal.impldep.aQute.lib.strings.Strings; import org.gradle.internal.impldep.aQute.lib.strings.Strings;
import org.zeroturnaround.zip.ZipUtil; import org.zeroturnaround.zip.ZipUtil;
import org.zeroturnaround.zip.commons.FileUtils; import org.zeroturnaround.zip.commons.FileUtils;
@ -48,7 +48,8 @@ import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; 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.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
@ -56,21 +57,24 @@ import java.util.zip.ZipEntry;
public class ModProcessor { public class ModProcessor {
private static final Gson GSON = new Gson(); 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()){ if(output.exists()){
output.delete(); output.delete();
} }
remapJar(input, output, project); remapJar(input, output, project);
readInstallerJson(input, project);
//Enable this if you want your nested jars to be extracted, this will extract **all** jars //Enable this if you want your nested jars to be extracted, this will extract **all** jars
if(project.getExtensions().getByType(LoomGradleExtension.class).extractJars){ if(project.getExtensions().getByType(LoomGradleExtension.class).extractJars){
handleNestedJars(input, project); handleNestedJars(input, project, config);
} }
//Always strip the nested jars //Always strip the nested jars
stripNestedJars(output); 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); JarFile jarFile = new JarFile(input);
JarEntry modJsonEntry = jarFile.getJarEntry("fabric.mod.json"); JarEntry modJsonEntry = jarFile.getJarEntry("fabric.mod.json");
if(modJsonEntry == null){ if(modJsonEntry == null){
@ -86,12 +90,12 @@ public class ModProcessor {
JsonObject jsonObject = jsonArray.get(i).getAsJsonObject(); JsonObject jsonObject = jsonArray.get(i).getAsJsonObject();
String fileName = jsonObject.get("file").getAsString(); String fileName = jsonObject.get("file").getAsString();
project.getLogger().lifecycle(String.format("Found %s nested in %s", fileName, input.getName())); 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); LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
JarEntry entry = parentJar.getJarEntry(fileName); JarEntry entry = parentJar.getJarEntry(fileName);
@ -105,14 +109,14 @@ public class ModProcessor {
} }
File remappedFile = new File(extension.getRemappedModCache(), fileName.substring(fileName.lastIndexOf("/"))); File remappedFile = new File(extension.getRemappedModCache(), fileName.substring(fileName.lastIndexOf("/")));
handleMod(nestedFile, remappedFile, project); processMod(nestedFile, remappedFile, project, config);
if(!remappedFile.exists()){ if(!remappedFile.exists()){
throw new RuntimeException("Failed to find processed nested jar"); throw new RuntimeException("Failed to find processed nested jar");
} }
//Add the project right onto the remapped mods, hopefully this works //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){ private static void stripNestedJars(File file){
@ -142,7 +146,9 @@ public class ModProcessor {
Path[] mcDeps = mappedProvider.getMapperPaths().stream() Path[] mcDeps = mappedProvider.getMapperPaths().stream()
.map(File::toPath) .map(File::toPath)
.toArray(Path[]::new); .toArray(Path[]::new);
Path[] modCompiles = project.getConfigurations().getByName(Constants.COMPILE_MODS).getFiles().stream() Set<Path> modCompiles = new HashSet<>();
for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) {
project.getConfigurations().getByName(entry.getSourceConfiguration()).getFiles().stream()
.filter((f) -> !f.equals(input)) .filter((f) -> !f.equals(input))
.map(p -> { .map(p -> {
if (p.equals(input)) { if (p.equals(input)) {
@ -151,7 +157,9 @@ public class ModProcessor {
return p.toPath(); return p.toPath();
} }
}) })
.toArray(Path[]::new); .forEach(modCompiles::add);
}
project.getLogger().lifecycle(":remapping " + input.getName() + " (TinyRemapper, " + fromM + " -> " + toM + ")"); 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()))) { try (OutputConsumerPath outputConsumer = new OutputConsumerPath(Paths.get(output.getAbsolutePath()))) {
outputConsumer.addNonClassFiles(inputPath); outputConsumer.addNonClassFiles(inputPath);
remapper.readClassPath(modCompiles); remapper.readClassPath(modCompiles.toArray(new Path[0]));
remapper.readClassPath(mc); remapper.readClassPath(mc);
remapper.readClassPath(mcDeps); remapper.readClassPath(mcDeps);
remapper.readInputs(inputPath); remapper.readInputs(inputPath);
@ -194,7 +202,7 @@ public class ModProcessor {
if (entry == null) { if (entry == null) {
entry = jarFile.getEntry("fabric-installer.json"); entry = jarFile.getEntry("fabric-installer.json");
priority = 1; priority++;
if (entry == null) { if (entry == null) {
return; 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"); 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()) { for (File file : project.getConfigurations().getByName(Constants.MINECRAFT_DEPENDENCIES).getFiles()) {
mercury.getClassPath().add(file.toPath()); m.getClassPath().add(file.toPath());
} }
if (!toNamed) { if (!toNamed) {
for (File file : project.getConfigurations().getByName(Constants.COMPILE_MODS_MAPPED).getFiles()) { for (File file : project.getConfigurations().getByName("compileClasspath").getFiles()) {
mercury.getClassPath().add(file.toPath()); m.getClassPath().add(file.toPath());
} }
} }
for (Path file : extension.getUnmappedMods()) { for (Path file : extension.getUnmappedMods()) {
if (Files.isRegularFile(file)) { if (Files.isRegularFile(file)) {
mercury.getClassPath().add(file); m.getClassPath().add(file);
} }
} }
mercury.getClassPath().add(extension.getMinecraftMappedProvider().MINECRAFT_MAPPED_JAR.toPath()); m.getClassPath().add(extension.getMinecraftMappedProvider().MINECRAFT_MAPPED_JAR.toPath());
mercury.getClassPath().add(extension.getMinecraftMappedProvider().MINECRAFT_INTERMEDIARY_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.equals(destination)) {
if (source.isDirectory()) { if (source.isDirectory()) {