Rewrire Jar and Source remapping tasks. (#504)
This commit is contained in:
parent
5a16440c1e
commit
ab21e0e550
36 changed files with 1154 additions and 1423 deletions
|
@ -26,7 +26,6 @@ package net.fabricmc.loom;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.cadixdev.lorenz.MappingSet;
|
import org.cadixdev.lorenz.MappingSet;
|
||||||
|
@ -36,6 +35,8 @@ import org.gradle.api.NamedDomainObjectProvider;
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
import org.gradle.api.artifacts.Configuration;
|
import org.gradle.api.artifacts.Configuration;
|
||||||
import org.gradle.api.file.ConfigurableFileCollection;
|
import org.gradle.api.file.ConfigurableFileCollection;
|
||||||
|
import org.gradle.api.file.FileCollection;
|
||||||
|
import org.gradle.api.tasks.SourceSet;
|
||||||
|
|
||||||
import net.fabricmc.loom.api.LoomGradleExtensionAPI;
|
import net.fabricmc.loom.api.LoomGradleExtensionAPI;
|
||||||
import net.fabricmc.loom.configuration.InstallerData;
|
import net.fabricmc.loom.configuration.InstallerData;
|
||||||
|
@ -94,9 +95,9 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI {
|
||||||
return getMappingsProvider().mappedProvider;
|
return getMappingsProvider().mappedProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
File getNextMixinMappings();
|
File getMixinMappings(SourceSet sourceSet);
|
||||||
|
|
||||||
Set<File> getAllMixinMappings();
|
FileCollection getAllMixinMappings();
|
||||||
|
|
||||||
boolean isRootProject();
|
boolean isRootProject();
|
||||||
|
|
||||||
|
|
|
@ -1,159 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 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;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
|
|
||||||
import org.gradle.api.Action;
|
|
||||||
import org.objectweb.asm.commons.Remapper;
|
|
||||||
|
|
||||||
import net.fabricmc.loom.util.CloseableList;
|
|
||||||
import net.fabricmc.stitch.util.Pair;
|
|
||||||
import net.fabricmc.tinyremapper.IMappingProvider;
|
|
||||||
import net.fabricmc.tinyremapper.InputTag;
|
|
||||||
import net.fabricmc.tinyremapper.OutputConsumerPath;
|
|
||||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
|
||||||
|
|
||||||
public class JarRemapper {
|
|
||||||
private final List<IMappingProvider> mappingProviders = new ArrayList<>();
|
|
||||||
private final Set<Path> classPath = new HashSet<>();
|
|
||||||
private final List<RemapData> remapData = new ArrayList<>();
|
|
||||||
private List<Action<TinyRemapper.Builder>> remapOptions;
|
|
||||||
|
|
||||||
public void addMappings(IMappingProvider mappingProvider) {
|
|
||||||
mappingProviders.add(mappingProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addToClasspath(Path... paths) {
|
|
||||||
classPath.addAll(Arrays.asList(paths));
|
|
||||||
}
|
|
||||||
|
|
||||||
public RemapData scheduleRemap(Path input, Path output) {
|
|
||||||
RemapData data = new RemapData(input, output);
|
|
||||||
remapData.add(data);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remap() throws IOException {
|
|
||||||
TinyRemapper.Builder remapperBuilder = TinyRemapper.newRemapper();
|
|
||||||
mappingProviders.forEach(remapperBuilder::withMappings);
|
|
||||||
|
|
||||||
if (remapOptions != null) {
|
|
||||||
for (Action<TinyRemapper.Builder> remapOption : remapOptions) {
|
|
||||||
remapOption.execute(remapperBuilder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TinyRemapper remapper = remapperBuilder.build();
|
|
||||||
|
|
||||||
Path[] remapClasspath = classPath.stream()
|
|
||||||
.filter(path ->
|
|
||||||
remapData.stream().noneMatch(remapData -> remapData.input.equals(path))
|
|
||||||
)
|
|
||||||
.toArray(Path[]::new);
|
|
||||||
|
|
||||||
remapper.readClassPathAsync(remapClasspath);
|
|
||||||
|
|
||||||
for (RemapData data : remapData) {
|
|
||||||
InputTag tag = remapper.createInputTag();
|
|
||||||
data.tag = tag;
|
|
||||||
remapper.readInputsAsync(tag, data.input);
|
|
||||||
}
|
|
||||||
|
|
||||||
//noinspection MismatchedQueryAndUpdateOfCollection
|
|
||||||
try (CloseableList<OutputConsumerPath> outputConsumers = new CloseableList<>()) {
|
|
||||||
for (RemapData data : remapData) {
|
|
||||||
OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(data.output).build();
|
|
||||||
outputConsumers.add(outputConsumer);
|
|
||||||
|
|
||||||
outputConsumer.addNonClassFiles(data.input);
|
|
||||||
|
|
||||||
data.processAccessWidener(remapper.getEnvironment().getRemapper());
|
|
||||||
remapper.apply(outputConsumer, data.tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
remapper.finish();
|
|
||||||
} catch (Exception e) {
|
|
||||||
for (RemapData data : remapData) {
|
|
||||||
// Cleanup bad outputs
|
|
||||||
Files.deleteIfExists(data.output);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IOException("Failed to remap %s files".formatted(remapData.size()), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
remapData.forEach(RemapData::complete);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addOptions(List<Action<TinyRemapper.Builder>> remapOptions) {
|
|
||||||
this.remapOptions = remapOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class RemapData {
|
|
||||||
public final Path input;
|
|
||||||
public final Path output;
|
|
||||||
BiFunction<RemapData, Remapper, Pair<String, byte[]>> accesWidenerSupplier;
|
|
||||||
BiConsumer<RemapData, Pair<String, byte[]>> onComplete;
|
|
||||||
|
|
||||||
private InputTag tag;
|
|
||||||
private Pair<String, byte[]> accessWidener;
|
|
||||||
|
|
||||||
public RemapData(Path input, Path output) {
|
|
||||||
this.input = input;
|
|
||||||
this.output = output;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RemapData complete(BiConsumer<RemapData, Pair<String, byte[]>> onComplete) {
|
|
||||||
this.onComplete = onComplete;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RemapData supplyAccessWidener(BiFunction<RemapData, Remapper, Pair<String, byte[]>> beforeFinish) {
|
|
||||||
this.accesWidenerSupplier = beforeFinish;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void complete() {
|
|
||||||
if (onComplete != null) {
|
|
||||||
onComplete.accept(this, accessWidener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processAccessWidener(Remapper remapper) {
|
|
||||||
if (accesWidenerSupplier != null) {
|
|
||||||
accessWidener = accesWidenerSupplier.apply(this, remapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -27,13 +27,9 @@ package net.fabricmc.loom.build;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.UncheckedIOException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
@ -41,74 +37,35 @@ import java.util.zip.ZipFile;
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonPrimitive;
|
import com.google.gson.JsonPrimitive;
|
||||||
import org.gradle.api.Project;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
|
||||||
import net.fabricmc.loom.LoomGradlePlugin;
|
import net.fabricmc.loom.LoomGradlePlugin;
|
||||||
import net.fabricmc.loom.extension.MixinExtension;
|
|
||||||
import net.fabricmc.loom.util.Pair;
|
|
||||||
import net.fabricmc.loom.util.ZipUtils;
|
|
||||||
|
|
||||||
public final class MixinRefmapHelper {
|
public final class MixinRefmapHelper {
|
||||||
private MixinRefmapHelper() { }
|
private MixinRefmapHelper() { }
|
||||||
|
|
||||||
private static final String FABRIC_MOD_JSON = "fabric.mod.json";
|
private static final String FABRIC_MOD_JSON = "fabric.mod.json";
|
||||||
|
|
||||||
public static boolean addRefmapName(Project project, Path outputPath) {
|
@Nullable
|
||||||
try {
|
public static JsonObject readFabricModJson(File output) {
|
||||||
MixinExtension mixin = LoomGradleExtension.get(project).getMixin();
|
|
||||||
File output = outputPath.toFile();
|
|
||||||
|
|
||||||
Collection<String> allMixinConfigs = getMixinConfigurationFiles(readFabricModJson(output));
|
|
||||||
|
|
||||||
return mixin.getMixinSourceSetsStream().map(sourceSet -> {
|
|
||||||
MixinExtension.MixinInformationContainer container = Objects.requireNonNull(
|
|
||||||
MixinExtension.getMixinInformationContainer(sourceSet)
|
|
||||||
);
|
|
||||||
|
|
||||||
Stream<String> mixinConfigs = sourceSet.getResources()
|
|
||||||
.matching(container.mixinConfigPattern())
|
|
||||||
.getFiles()
|
|
||||||
.stream()
|
|
||||||
.map(File::getName)
|
|
||||||
.filter(allMixinConfigs::contains);
|
|
||||||
|
|
||||||
String refmapName = container.refmapNameProvider().get();
|
|
||||||
|
|
||||||
try {
|
|
||||||
return ZipUtils.transformJson(JsonObject.class, outputPath, mixinConfigs.map(f -> new Pair<>(f, json -> {
|
|
||||||
if (!json.has("refmap")) {
|
|
||||||
json.addProperty("refmap", refmapName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return json;
|
|
||||||
}))) > 0;
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new UncheckedIOException("Failed to transform mixin configs in jar", e);
|
|
||||||
}
|
|
||||||
}).reduce(false, Boolean::logicalOr);
|
|
||||||
} catch (Exception e) {
|
|
||||||
project.getLogger().error(e.getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static JsonObject readFabricModJson(File output) {
|
|
||||||
try (ZipFile zip = new ZipFile(output)) {
|
try (ZipFile zip = new ZipFile(output)) {
|
||||||
ZipEntry entry = zip.getEntry(FABRIC_MOD_JSON);
|
ZipEntry entry = zip.getEntry(FABRIC_MOD_JSON);
|
||||||
|
|
||||||
|
if (entry == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
try (InputStreamReader reader = new InputStreamReader(zip.getInputStream(entry))) {
|
try (InputStreamReader reader = new InputStreamReader(zip.getInputStream(entry))) {
|
||||||
return LoomGradlePlugin.GSON.fromJson(reader, JsonObject.class);
|
return LoomGradlePlugin.GSON.fromJson(reader, JsonObject.class);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException("Cannot read file fabric.mod.json in the output jar.", e);
|
throw new RuntimeException("Cannot read file fabric.mod.json in the jar.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static Collection<String> getMixinConfigurationFiles(JsonObject fabricModJson) {
|
public static Collection<String> getMixinConfigurationFiles(JsonObject fabricModJson) {
|
||||||
JsonArray mixins = fabricModJson.getAsJsonArray("mixins");
|
JsonArray mixins = fabricModJson.getAsJsonArray("mixins");
|
||||||
|
|
||||||
if (mixins == null) {
|
if (mixins == null) {
|
||||||
|
|
|
@ -84,7 +84,7 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
|
||||||
String refmapName = Objects.requireNonNull(MixinExtension.getMixinInformationContainer(sourceSet)).refmapNameProvider().get();
|
String refmapName = Objects.requireNonNull(MixinExtension.getMixinInformationContainer(sourceSet)).refmapNameProvider().get();
|
||||||
Map<String, String> args = new HashMap<>() {{
|
Map<String, String> args = new HashMap<>() {{
|
||||||
put(Constants.MixinArguments.IN_MAP_FILE_NAMED_INTERMEDIARY, loom.getMappingsProvider().tinyMappings.toFile().getCanonicalPath());
|
put(Constants.MixinArguments.IN_MAP_FILE_NAMED_INTERMEDIARY, loom.getMappingsProvider().tinyMappings.toFile().getCanonicalPath());
|
||||||
put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, loom.getNextMixinMappings().getCanonicalPath());
|
put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, loom.getMixinMappings(sourceSet).getCanonicalPath());
|
||||||
put(Constants.MixinArguments.OUT_REFMAP_FILE, getRefmapDestination(task, refmapName));
|
put(Constants.MixinArguments.OUT_REFMAP_FILE, getRefmapDestination(task, refmapName));
|
||||||
put(Constants.MixinArguments.DEFAULT_OBFUSCATION_ENV, "named:intermediary");
|
put(Constants.MixinArguments.DEFAULT_OBFUSCATION_ENV, "named:intermediary");
|
||||||
}};
|
}};
|
||||||
|
|
|
@ -0,0 +1,203 @@
|
||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.build.nesting;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.Task;
|
||||||
|
import org.gradle.api.artifacts.Configuration;
|
||||||
|
import org.gradle.api.artifacts.Dependency;
|
||||||
|
import org.gradle.api.artifacts.ProjectDependency;
|
||||||
|
import org.gradle.api.artifacts.ResolvedArtifact;
|
||||||
|
import org.gradle.api.artifacts.ResolvedConfiguration;
|
||||||
|
import org.gradle.api.artifacts.ResolvedDependency;
|
||||||
|
import org.gradle.api.file.ConfigurableFileCollection;
|
||||||
|
import org.gradle.api.plugins.JavaPlugin;
|
||||||
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.gradle.api.tasks.bundling.AbstractArchiveTask;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
|
import net.fabricmc.loom.LoomGradlePlugin;
|
||||||
|
import net.fabricmc.loom.task.RemapTaskConfiguration;
|
||||||
|
import net.fabricmc.loom.util.ModUtils;
|
||||||
|
import net.fabricmc.loom.util.ZipUtils;
|
||||||
|
|
||||||
|
public final class IncludedJarFactory {
|
||||||
|
private final Project project;
|
||||||
|
|
||||||
|
public IncludedJarFactory(Project project) {
|
||||||
|
this.project = project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Provider<ConfigurableFileCollection> getNestedJars(final Configuration configuration) {
|
||||||
|
return project.provider(() -> {
|
||||||
|
final ConfigurableFileCollection files = project.files();
|
||||||
|
final Set<String> visited = Sets.newHashSet();
|
||||||
|
|
||||||
|
files.from(getProjectDeps(configuration, visited));
|
||||||
|
files.from(getFileDeps(configuration, visited));
|
||||||
|
files.builtBy(configuration.getBuildDependencies());
|
||||||
|
return files;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConfigurableFileCollection getFileDeps(Configuration configuration, Set<String> visited) {
|
||||||
|
final ConfigurableFileCollection files = project.files();
|
||||||
|
|
||||||
|
final ResolvedConfiguration resolvedConfiguration = configuration.getResolvedConfiguration();
|
||||||
|
final Set<ResolvedDependency> dependencies = resolvedConfiguration.getFirstLevelModuleDependencies();
|
||||||
|
|
||||||
|
for (ResolvedDependency dependency : dependencies) {
|
||||||
|
if (!visited.add(dependency.getModuleGroup() + ":" + dependency.getModuleName() + ":" + dependency.getModuleVersion())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ResolvedArtifact artifact : dependency.getModuleArtifacts()) {
|
||||||
|
Metadata metadata = new Metadata(
|
||||||
|
dependency.getModuleGroup(),
|
||||||
|
dependency.getModuleName(),
|
||||||
|
dependency.getModuleVersion(),
|
||||||
|
artifact.getClassifier()
|
||||||
|
);
|
||||||
|
|
||||||
|
files.from(project.provider(() -> getNestableJar(artifact.getFile(), metadata)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConfigurableFileCollection getProjectDeps(Configuration configuration, Set<String> visited) {
|
||||||
|
final ConfigurableFileCollection files = project.files();
|
||||||
|
|
||||||
|
for (Dependency dependency : configuration.getDependencies()) {
|
||||||
|
if (dependency instanceof ProjectDependency projectDependency) {
|
||||||
|
if (!visited.add(dependency.getGroup() + ":" + dependency.getName() + ":" + dependency.getVersion())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the outputs of the project
|
||||||
|
final Project dependentProject = projectDependency.getDependencyProject();
|
||||||
|
|
||||||
|
Collection<Task> remapJarTasks = dependentProject.getTasksByName(RemapTaskConfiguration.REMAP_JAR_TASK_NAME, false);
|
||||||
|
Collection<Task> jarTasks = dependentProject.getTasksByName(JavaPlugin.JAR_TASK_NAME, false);
|
||||||
|
|
||||||
|
if (remapJarTasks.isEmpty() && jarTasks.isEmpty()) {
|
||||||
|
throw new UnsupportedOperationException("%s does not have a remapJar or jar task, cannot nest it".formatted(dependentProject.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Task task : remapJarTasks.isEmpty() ? jarTasks : remapJarTasks) {
|
||||||
|
if (task instanceof AbstractArchiveTask archiveTask) {
|
||||||
|
final Metadata metadata = new Metadata(
|
||||||
|
projectDependency.getGroup(),
|
||||||
|
projectDependency.getName(),
|
||||||
|
projectDependency.getVersion(),
|
||||||
|
archiveTask.getArchiveClassifier().getOrNull()
|
||||||
|
);
|
||||||
|
|
||||||
|
Provider<File> provider = archiveTask.getArchiveFile().map(regularFile -> getNestableJar(regularFile.getAsFile(), metadata));
|
||||||
|
files.from(provider);
|
||||||
|
files.builtBy(task);
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("Cannot nest none AbstractArchiveTask task: " + task.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
private File getNestableJar(final File input, final Metadata metadata) {
|
||||||
|
if (ModUtils.isMod(input)) {
|
||||||
|
// Input is a mod, nothing needs to be done.
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||||
|
File tempDir = new File(extension.getFiles().getUserCache(), "temp/modprocessing");
|
||||||
|
|
||||||
|
if (!tempDir.exists()) {
|
||||||
|
tempDir.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
File tempFile = new File(tempDir, input.getName());
|
||||||
|
|
||||||
|
if (tempFile.exists()) {
|
||||||
|
tempFile.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileUtils.copyFile(input, tempFile);
|
||||||
|
ZipUtils.add(tempFile.toPath(), "fabric.mod.json", generateModForDependency(metadata).getBytes(StandardCharsets.UTF_8));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException("Failed to add dummy mod while including %s".formatted(input), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tempFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generates a barebones mod for a dependency
|
||||||
|
private static String generateModForDependency(Metadata metadata) {
|
||||||
|
final String modId = (metadata.group() + "_" + metadata.name() + metadata.classifier())
|
||||||
|
.replaceAll("\\.", "_")
|
||||||
|
.toLowerCase(Locale.ENGLISH);
|
||||||
|
|
||||||
|
final JsonObject jsonObject = new JsonObject();
|
||||||
|
jsonObject.addProperty("schemaVersion", 1);
|
||||||
|
|
||||||
|
jsonObject.addProperty("id", modId);
|
||||||
|
jsonObject.addProperty("version", metadata.version());
|
||||||
|
jsonObject.addProperty("name", metadata.name());
|
||||||
|
|
||||||
|
JsonObject custom = new JsonObject();
|
||||||
|
custom.addProperty("fabric-loom:generated", true);
|
||||||
|
jsonObject.add("custom", custom);
|
||||||
|
|
||||||
|
return LoomGradlePlugin.GSON.toJson(jsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Metadata(String group, String name, String version, @Nullable String classifier) {
|
||||||
|
@Override
|
||||||
|
public String classifier() {
|
||||||
|
if (classifier == null) {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
return "_" + classifier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,7 +36,7 @@ import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import org.gradle.api.UncheckedIOException;
|
import org.gradle.api.UncheckedIOException;
|
||||||
import org.gradle.api.logging.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import net.fabricmc.loom.util.ModUtils;
|
import net.fabricmc.loom.util.ModUtils;
|
||||||
import net.fabricmc.loom.util.Pair;
|
import net.fabricmc.loom.util.Pair;
|
||||||
|
@ -69,6 +69,7 @@ public class JarNester {
|
||||||
|
|
||||||
for (File file : jars) {
|
for (File file : jars) {
|
||||||
String nestedJarPath = "META-INF/jars/" + file.getName();
|
String nestedJarPath = "META-INF/jars/" + file.getName();
|
||||||
|
Preconditions.checkArgument(ModUtils.isMod(file), "Cannot nest none mod jar: " + file.getName());
|
||||||
|
|
||||||
for (JsonElement nestedJar : nestedJars) {
|
for (JsonElement nestedJar : nestedJars) {
|
||||||
JsonObject jsonObject = nestedJar.getAsJsonObject();
|
JsonObject jsonObject = nestedJar.getAsJsonObject();
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
|
||||||
*
|
|
||||||
* Copyright (c) 2016-2021 FabricMC
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.fabricmc.loom.build.nesting;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.gradle.api.Project;
|
|
||||||
|
|
||||||
public record MergedNestedJarProvider(NestedJarProvider... children) implements NestedJarProvider {
|
|
||||||
@Override
|
|
||||||
public Collection<File> provide() {
|
|
||||||
return Arrays.stream(children)
|
|
||||||
.map(NestedJarProvider::provide)
|
|
||||||
.flatMap(Collection::stream)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void prepare(Project project) {
|
|
||||||
Arrays.stream(children).forEach(nestedJarProvider -> nestedJarProvider.prepare(project));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,282 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
|
||||||
*
|
|
||||||
* Copyright (c) 2019-2021 FabricMC
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.fabricmc.loom.build.nesting;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.UncheckedIOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.gradle.api.Project;
|
|
||||||
import org.gradle.api.Task;
|
|
||||||
import org.gradle.api.artifacts.Configuration;
|
|
||||||
import org.gradle.api.artifacts.Dependency;
|
|
||||||
import org.gradle.api.artifacts.DependencySet;
|
|
||||||
import org.gradle.api.artifacts.ProjectDependency;
|
|
||||||
import org.gradle.api.artifacts.ResolvedArtifact;
|
|
||||||
import org.gradle.api.artifacts.ResolvedConfiguration;
|
|
||||||
import org.gradle.api.artifacts.ResolvedDependency;
|
|
||||||
import org.gradle.api.tasks.bundling.AbstractArchiveTask;
|
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
|
||||||
import net.fabricmc.loom.LoomGradlePlugin;
|
|
||||||
import net.fabricmc.loom.task.RemapJarTask;
|
|
||||||
import net.fabricmc.loom.util.Constants;
|
|
||||||
import net.fabricmc.loom.util.ModUtils;
|
|
||||||
import net.fabricmc.loom.util.ZipUtils;
|
|
||||||
|
|
||||||
public final class NestedDependencyProvider implements NestedJarProvider {
|
|
||||||
final Project project;
|
|
||||||
final List<DependencyInfo<?>> files;
|
|
||||||
|
|
||||||
private NestedDependencyProvider(Project project, List<DependencyInfo<?>> files) {
|
|
||||||
this.project = project;
|
|
||||||
this.files = files;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NestedDependencyProvider createNestedDependencyProviderFromConfiguration(Project project, Configuration configuration) {
|
|
||||||
List<DependencyInfo<?>> fileList = new ArrayList<>();
|
|
||||||
Set<String> visited = new HashSet<>();
|
|
||||||
|
|
||||||
fileList.addAll(populateProjectDependencies(configuration, visited));
|
|
||||||
fileList.addAll(populateResolvedDependencies(configuration, visited));
|
|
||||||
|
|
||||||
return new NestedDependencyProvider(project, fileList);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Looks for any deps that require a sub project to be built first
|
|
||||||
public static List<RemapJarTask> getRequiredTasks(Project project) {
|
|
||||||
List<RemapJarTask> remapTasks = new ArrayList<>();
|
|
||||||
|
|
||||||
Configuration configuration = project.getConfigurations().getByName(Constants.Configurations.INCLUDE);
|
|
||||||
DependencySet dependencies = configuration.getDependencies();
|
|
||||||
|
|
||||||
for (Dependency dependency : dependencies) {
|
|
||||||
if (dependency instanceof ProjectDependency projectDependency) {
|
|
||||||
Project dependencyProject = projectDependency.getDependencyProject();
|
|
||||||
|
|
||||||
for (Task task : dependencyProject.getTasksByName("remapJar", false)) {
|
|
||||||
if (task instanceof RemapJarTask remapJarTask) {
|
|
||||||
remapTasks.add(remapJarTask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return remapTasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<DependencyInfo<ProjectDependency>> populateProjectDependencies(Configuration configuration, Set<String> visited) {
|
|
||||||
List<DependencyInfo<ProjectDependency>> fileList = new ArrayList<>();
|
|
||||||
|
|
||||||
for (Dependency dependency : configuration.getDependencies()) {
|
|
||||||
if (dependency instanceof ProjectDependency projectDependency) {
|
|
||||||
Project dependencyProject = projectDependency.getDependencyProject();
|
|
||||||
|
|
||||||
visited.add(dependency.getGroup() + ":" + dependency.getName() + ":" + dependency.getVersion());
|
|
||||||
|
|
||||||
Collection<Task> remapJarTasks = dependencyProject.getTasksByName("remapJar", false);
|
|
||||||
Collection<Task> jarTasks = dependencyProject.getTasksByName("jar", false);
|
|
||||||
|
|
||||||
for (Task task : remapJarTasks.isEmpty() ? jarTasks : remapJarTasks) {
|
|
||||||
if (task instanceof AbstractArchiveTask abstractArchiveTask) {
|
|
||||||
fileList.add(new DependencyInfo<>(
|
|
||||||
projectDependency,
|
|
||||||
new ProjectDependencyMetaExtractor(),
|
|
||||||
abstractArchiveTask.getArchiveFile().get().getAsFile(),
|
|
||||||
abstractArchiveTask.getArchiveClassifier().getOrNull()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ResolvedArtifact artifact : dependency.getModuleArtifacts()) {
|
|
||||||
fileList.add(new DependencyInfo<>(
|
|
||||||
dependency,
|
|
||||||
new ResolvedDependencyMetaExtractor(),
|
|
||||||
artifact.getFile(),
|
|
||||||
artifact.getClassifier()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
if (!ModUtils.isMod(file)) {
|
|
||||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
|
||||||
File tempDir = new File(extension.getFiles().getUserCache(), "temp/modprocessing");
|
|
||||||
|
|
||||||
if (!tempDir.exists()) {
|
|
||||||
tempDir.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
File tempFile = new File(tempDir, file.getName());
|
|
||||||
|
|
||||||
if (tempFile.exists()) {
|
|
||||||
tempFile.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
FileUtils.copyFile(file, tempFile);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Failed to copy file", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
ZipUtils.add(tempFile.toPath(), "fabric.mod.json", generateModForDependency(metaFile).getBytes());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new UncheckedIOException("Failed to add dummy mod while including %s".formatted(file), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
fileList.add(tempFile);
|
|
||||||
} else {
|
|
||||||
// Default copy the jar right in
|
|
||||||
fileList.add(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fileList;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates a barebones mod for a dependency
|
|
||||||
private static <D> String generateModForDependency(DependencyInfo<D> info) {
|
|
||||||
DependencyMetaExtractor<D> metaExtractor = info.metaExtractor;
|
|
||||||
D dependency = info.dependency;
|
|
||||||
|
|
||||||
JsonObject jsonObject = new JsonObject();
|
|
||||||
jsonObject.addProperty("schemaVersion", 1);
|
|
||||||
|
|
||||||
jsonObject.addProperty("id",
|
|
||||||
(metaExtractor.group(dependency) + "_" + metaExtractor.name(dependency) + info.getClassifierSuffix())
|
|
||||||
.replaceAll("\\.", "_")
|
|
||||||
.toLowerCase(Locale.ENGLISH)
|
|
||||||
);
|
|
||||||
jsonObject.addProperty("version", metaExtractor.version(dependency));
|
|
||||||
jsonObject.addProperty("name", metaExtractor.name(dependency));
|
|
||||||
|
|
||||||
JsonObject custom = new JsonObject();
|
|
||||||
custom.addProperty("fabric-loom:generated", true);
|
|
||||||
jsonObject.add("custom", custom);
|
|
||||||
|
|
||||||
return LoomGradlePlugin.GSON.toJson(jsonObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
private record DependencyInfo<D>(D dependency, DependencyMetaExtractor<D> metaExtractor, File file, @Nullable String classifier) {
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String getClassifierSuffix() {
|
|
||||||
if (classifier == null) {
|
|
||||||
return "";
|
|
||||||
} else {
|
|
||||||
return "_" + classifier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private interface DependencyMetaExtractor<D> {
|
|
||||||
String group(D dependency);
|
|
||||||
|
|
||||||
String version(D dependency);
|
|
||||||
|
|
||||||
String name(D dependency);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class ProjectDependencyMetaExtractor implements DependencyMetaExtractor<ProjectDependency> {
|
|
||||||
@Override
|
|
||||||
public String group(ProjectDependency dependency) {
|
|
||||||
return dependency.getGroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String version(ProjectDependency dependency) {
|
|
||||||
return dependency.getVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String name(ProjectDependency dependency) {
|
|
||||||
return dependency.getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class ResolvedDependencyMetaExtractor implements DependencyMetaExtractor<ResolvedDependency> {
|
|
||||||
@Override
|
|
||||||
public String group(ResolvedDependency dependency) {
|
|
||||||
return dependency.getModuleGroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String version(ResolvedDependency dependency) {
|
|
||||||
return dependency.getModuleVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String name(ResolvedDependency dependency) {
|
|
||||||
return dependency.getModuleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
|
||||||
*
|
|
||||||
* Copyright (c) 2016-2021 FabricMC
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.fabricmc.loom.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() {
|
|
||||||
Preconditions.checkNotNull(files, "null files to nest, was prepare called?");
|
|
||||||
|
|
||||||
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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
|
||||||
*
|
|
||||||
* Copyright (c) 2016-2021 FabricMC
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.fabricmc.loom.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) { }
|
|
||||||
}
|
|
|
@ -35,7 +35,6 @@ import org.gradle.api.tasks.AbstractCopyTask;
|
||||||
import org.gradle.api.tasks.SourceSet;
|
import org.gradle.api.tasks.SourceSet;
|
||||||
import org.gradle.api.tasks.compile.JavaCompile;
|
import org.gradle.api.tasks.compile.JavaCompile;
|
||||||
import org.gradle.api.tasks.javadoc.Javadoc;
|
import org.gradle.api.tasks.javadoc.Javadoc;
|
||||||
import org.gradle.jvm.tasks.Jar;
|
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.build.mixin.JavaApInvoker;
|
import net.fabricmc.loom.build.mixin.JavaApInvoker;
|
||||||
|
@ -124,6 +123,7 @@ public final class CompileConfiguration {
|
||||||
|
|
||||||
public static void configureCompile(Project p) {
|
public static void configureCompile(Project p) {
|
||||||
final JavaPluginExtension javaPluginExtension = p.getExtensions().getByType(JavaPluginExtension.class);
|
final JavaPluginExtension javaPluginExtension = p.getExtensions().getByType(JavaPluginExtension.class);
|
||||||
|
LoomGradleExtension extension = LoomGradleExtension.get(p);
|
||||||
|
|
||||||
SourceSet main = javaPluginExtension.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME);
|
SourceSet main = javaPluginExtension.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME);
|
||||||
|
|
||||||
|
@ -131,8 +131,6 @@ public final class CompileConfiguration {
|
||||||
javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath()));
|
javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath()));
|
||||||
|
|
||||||
p.afterEvaluate(project -> {
|
p.afterEvaluate(project -> {
|
||||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
|
||||||
|
|
||||||
LoomDependencyManager dependencyManager = new LoomDependencyManager();
|
LoomDependencyManager dependencyManager = new LoomDependencyManager();
|
||||||
extension.setDependencyManager(dependencyManager);
|
extension.setDependencyManager(dependencyManager);
|
||||||
|
|
||||||
|
@ -148,14 +146,6 @@ public final class CompileConfiguration {
|
||||||
|
|
||||||
extension.getRemapArchives().finalizeValue();
|
extension.getRemapArchives().finalizeValue();
|
||||||
|
|
||||||
// Enables the default mod remapper
|
|
||||||
if (extension.getRemapArchives().get()) {
|
|
||||||
RemapConfiguration.setupDefaultRemap(project);
|
|
||||||
} else {
|
|
||||||
Jar jarTask = (Jar) project.getTasks().getByName("jar");
|
|
||||||
extension.getUnmappedModCollection().from(jarTask);
|
|
||||||
}
|
|
||||||
|
|
||||||
MixinExtension mixin = LoomGradleExtension.get(project).getMixin();
|
MixinExtension mixin = LoomGradleExtension.get(project).getMixin();
|
||||||
|
|
||||||
if (mixin.getUseLegacyMixinAp().get()) {
|
if (mixin.getUseLegacyMixinAp().get()) {
|
||||||
|
|
|
@ -1,92 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
|
||||||
*
|
|
||||||
* Copyright (c) 2021 FabricMC
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.fabricmc.loom.configuration;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.jar.Attributes;
|
|
||||||
import java.util.jar.Manifest;
|
|
||||||
|
|
||||||
import org.gradle.api.Project;
|
|
||||||
import org.gradle.api.artifacts.Dependency;
|
|
||||||
import org.gradle.util.GradleVersion;
|
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
|
||||||
import net.fabricmc.loom.LoomGradlePlugin;
|
|
||||||
import net.fabricmc.loom.util.Constants;
|
|
||||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
|
||||||
|
|
||||||
public final record JarManifestConfiguration(Project project) {
|
|
||||||
public void configure(Manifest manifest) {
|
|
||||||
// Dont set when running the reproducible build tests as it will break them when anything updates
|
|
||||||
if (Boolean.getBoolean("loom.test.reproducible")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
|
||||||
|
|
||||||
Attributes attributes = manifest.getMainAttributes();
|
|
||||||
Optional<String> tinyRemapperVersion = Optional.ofNullable(TinyRemapper.class.getPackage().getImplementationVersion());
|
|
||||||
|
|
||||||
attributes.putValue("Fabric-Gradle-Version", GradleVersion.current().getVersion());
|
|
||||||
attributes.putValue("Fabric-Loom-Version", LoomGradlePlugin.LOOM_VERSION);
|
|
||||||
attributes.putValue("Fabric-Mixin-Compile-Extensions-Version", Constants.Dependencies.Versions.MIXIN_COMPILE_EXTENSIONS);
|
|
||||||
attributes.putValue("Fabric-Minecraft-Version", extension.getMinecraftProvider().minecraftVersion());
|
|
||||||
tinyRemapperVersion.ifPresent(s -> attributes.putValue("Fabric-Tiny-Remapper-Version", s));
|
|
||||||
getLoaderVersion().ifPresent(s -> attributes.putValue("Fabric-Loader-Version", s));
|
|
||||||
|
|
||||||
// This can be overridden by mods if required
|
|
||||||
if (!attributes.containsKey("Fabric-Mixin-Version")) {
|
|
||||||
addMixinVersion(attributes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addMixinVersion(Attributes attributes) {
|
|
||||||
// Not super ideal that this uses the mod compile classpath, should prob look into making this not a thing at somepoint
|
|
||||||
Optional<Dependency> dependency = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES)
|
|
||||||
.getDependencies()
|
|
||||||
.stream()
|
|
||||||
.filter(dep -> "sponge-mixin".equals(dep.getName()))
|
|
||||||
.findFirst();
|
|
||||||
|
|
||||||
if (dependency.isEmpty()) {
|
|
||||||
project.getLogger().warn("Could not determine Mixin version for jar manifest");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
attributes.putValue("Fabric-Mixin-Version", dependency.get().getVersion());
|
|
||||||
attributes.putValue("Fabric-Mixin-Group", dependency.get().getGroup());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Optional<String> getLoaderVersion() {
|
|
||||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
|
||||||
|
|
||||||
if (extension.getInstallerData() == null) {
|
|
||||||
project.getLogger().warn("Could not determine fabric loader version for jar manifest");
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.of(extension.getInstallerData().version());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,220 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
|
||||||
*
|
|
||||||
* Copyright (c) 2021 FabricMC
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.fabricmc.loom.configuration;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import org.gradle.api.Action;
|
|
||||||
import org.gradle.api.Project;
|
|
||||||
import org.gradle.api.Task;
|
|
||||||
import org.gradle.api.UnknownTaskException;
|
|
||||||
import org.gradle.api.artifacts.ConfigurablePublishArtifact;
|
|
||||||
import org.gradle.api.artifacts.Configuration;
|
|
||||||
import org.gradle.api.artifacts.PublishArtifact;
|
|
||||||
import org.gradle.api.artifacts.dsl.ArtifactHandler;
|
|
||||||
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);
|
|
||||||
|
|
||||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
|
||||||
extension.getSetupRemappedVariants().finalizeValue();
|
|
||||||
|
|
||||||
if (extension.getSetupRemappedVariants().get()) {
|
|
||||||
ArtifactHandler artifacts = project.getArtifacts();
|
|
||||||
project.getTasks().named(DEFAULT_REMAP_JAR_TASK_NAME, task -> {
|
|
||||||
artifacts.add(JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, task, artifactConfigurationAction(task, DEFAULT_REMAP_JAR_TASK_NAME, project));
|
|
||||||
artifacts.add(JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME, task, artifactConfigurationAction(task, DEFAULT_REMAP_JAR_TASK_NAME, project));
|
|
||||||
});
|
|
||||||
project.getTasks().named(DEFAULT_REMAP_SOURCES_JAR_TASK_NAME, RemapSourcesJarTask.class, task -> {
|
|
||||||
if (!project.getConfigurations().getNames().contains(JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME)) {
|
|
||||||
// Sources jar may not have been created with withSourcesJar
|
|
||||||
project.getLogger().info("Not publishing sources jar as it was not found. Use java.withSourcesJar() to fix.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PublishArtifact artifact = artifacts.add(JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME, task.getOutput(), artifactConfigurationAction(task, DEFAULT_REMAP_ALL_SOURCES_TASK_NAME, project));
|
|
||||||
|
|
||||||
// Remove the existing artifact that does not run remapSourcesJar.
|
|
||||||
// It doesn't seem to hurt, but I'm not sure if the file-level duplicates cause issues.
|
|
||||||
Configuration configuration = project.getConfigurations().getByName(JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME);
|
|
||||||
configuration.getArtifacts().removeIf(a -> a != artifact && artifact.getFile().equals(a.getFile()));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Remove -dev jars from the default jar task
|
|
||||||
for (String configurationName : new String[] { JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME }) {
|
|
||||||
Configuration configuration = project.getConfigurations().getByName(configurationName);
|
|
||||||
configuration.getArtifacts().removeIf(artifact -> {
|
|
||||||
Task jarTask = project.getTasks().getByName(DEFAULT_JAR_TASK_NAME);
|
|
||||||
// if the artifact is a -dev jar and "builtBy jar"
|
|
||||||
return "dev".equals(artifact.getClassifier()) && artifact.getBuildDependencies().getDependencies(null).contains(jarTask);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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 = LoomGradleExtension.get(project);
|
|
||||||
AbstractArchiveTask jarTask = (AbstractArchiveTask) project.getTasks().getByName(jarTaskName);
|
|
||||||
RemapJarTask remapJarTask = (RemapJarTask) project.getTasks().findByName(remapJarTaskName);
|
|
||||||
|
|
||||||
assert remapJarTask != null;
|
|
||||||
|
|
||||||
if (!remapJarTask.getInput().isPresent() && isDefaultRemap) {
|
|
||||||
jarTask.getArchiveClassifier().convention("dev");
|
|
||||||
remapJarTask.getArchiveClassifier().convention("");
|
|
||||||
remapJarTask.getInput().convention(jarTask.getArchiveFile());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDefaultRemap) {
|
|
||||||
extension.getUnmappedModCollection().from(jarTask);
|
|
||||||
remapJarTask.getAddNestedDependencies().convention(true);
|
|
||||||
remapJarTask.getRemapAccessWidener().convention(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.getShareRemapCaches().get()) {
|
|
||||||
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.getInput().convention(sourcesTask.getArchiveFile());
|
|
||||||
remapSourcesJarTask.getOutput().convention(sourcesTask.getArchiveFile());
|
|
||||||
remapSourcesJarTask.dependsOn(project.getTasks().getByName(sourcesJarTaskName));
|
|
||||||
|
|
||||||
if (isDefaultRemap) {
|
|
||||||
// Do not use lambda here, see: https://github.com/gradle/gradle/pull/17087
|
|
||||||
//noinspection Convert2Lambda
|
|
||||||
remapSourcesJarTask.doLast(new Action<>() {
|
|
||||||
@Override
|
|
||||||
public void execute(Task task) {
|
|
||||||
project.getArtifacts().add("archives", remapSourcesJarTask.getOutput());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extension.getShareRemapCaches().get()) {
|
|
||||||
remapSourcesJarTask.setSourceRemapper(remapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
parentTask.dependsOn(remapSourcesJarTask);
|
|
||||||
} catch (UnknownTaskException ignored) {
|
|
||||||
// pass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Action<ConfigurablePublishArtifact> artifactConfigurationAction(Task standardTask, String sharedTaskName, Project project) {
|
|
||||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
|
||||||
|
|
||||||
return artifact -> {
|
|
||||||
Task remapTask = standardTask;
|
|
||||||
|
|
||||||
if (extension.getShareRemapCaches().get()) {
|
|
||||||
remapTask = project.getRootProject().getTasks().getByName(sharedTaskName);
|
|
||||||
}
|
|
||||||
|
|
||||||
artifact.builtBy(remapTask);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -37,7 +37,7 @@ import com.google.gson.JsonObject;
|
||||||
import net.fabricmc.loom.util.ZipUtils;
|
import net.fabricmc.loom.util.ZipUtils;
|
||||||
|
|
||||||
public record AccessWidenerFile(
|
public record AccessWidenerFile(
|
||||||
String name,
|
String path,
|
||||||
String modId,
|
String modId,
|
||||||
byte[] content
|
byte[] content
|
||||||
) {
|
) {
|
||||||
|
@ -83,7 +83,7 @@ public record AccessWidenerFile(
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = Objects.hash(name, modId);
|
int result = Objects.hash(path, modId);
|
||||||
result = 31 * result + Arrays.hashCode(content);
|
result = 31 * result + Arrays.hashCode(content);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,14 +34,10 @@ import java.util.Arrays;
|
||||||
|
|
||||||
import com.google.common.hash.Hashing;
|
import com.google.common.hash.Hashing;
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
import org.objectweb.asm.commons.Remapper;
|
|
||||||
|
|
||||||
import net.fabricmc.accesswidener.AccessWidener;
|
import net.fabricmc.accesswidener.AccessWidener;
|
||||||
import net.fabricmc.accesswidener.AccessWidenerReader;
|
import net.fabricmc.accesswidener.AccessWidenerReader;
|
||||||
import net.fabricmc.accesswidener.AccessWidenerRemapper;
|
|
||||||
import net.fabricmc.accesswidener.AccessWidenerWriter;
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
|
||||||
import net.fabricmc.loom.configuration.processors.JarProcessor;
|
import net.fabricmc.loom.configuration.processors.JarProcessor;
|
||||||
import net.fabricmc.loom.util.ZipUtils;
|
import net.fabricmc.loom.util.ZipUtils;
|
||||||
|
|
||||||
|
@ -96,25 +92,6 @@ public class AccessWidenerJarProcessor implements JarProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get this mods access widener remapped to the intermediary namespace.
|
|
||||||
*/
|
|
||||||
public byte[] getRemappedAccessWidener(Remapper asmRemapper, String targetNamespace) throws IOException {
|
|
||||||
int version = AccessWidenerReader.readVersion(modAccessWidener);
|
|
||||||
|
|
||||||
AccessWidenerWriter writer = new AccessWidenerWriter(version);
|
|
||||||
AccessWidenerRemapper remapper = new AccessWidenerRemapper(
|
|
||||||
writer,
|
|
||||||
asmRemapper,
|
|
||||||
MappingsNamespace.NAMED.toString(),
|
|
||||||
targetNamespace
|
|
||||||
);
|
|
||||||
AccessWidenerReader reader = new AccessWidenerReader(remapper);
|
|
||||||
reader.read(modAccessWidener);
|
|
||||||
|
|
||||||
return writer.write();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInvalid(File file) {
|
public boolean isInvalid(File file) {
|
||||||
byte[] hash;
|
byte[] hash;
|
||||||
|
|
|
@ -491,6 +491,10 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getBuildServiceName(String name, String from, String to) {
|
||||||
|
return "%s:%s:%s>%S".formatted(name, mappingsIdentifier(), from, to);
|
||||||
|
}
|
||||||
|
|
||||||
public record UnpickMetadata(String unpickGroup, String unpickVersion) {
|
public record UnpickMetadata(String unpickGroup, String unpickVersion) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,10 @@ package net.fabricmc.loom.extension;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.cadixdev.lorenz.MappingSet;
|
import org.cadixdev.lorenz.MappingSet;
|
||||||
|
@ -42,6 +39,8 @@ import org.gradle.api.NamedDomainObjectProvider;
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
import org.gradle.api.artifacts.Configuration;
|
import org.gradle.api.artifacts.Configuration;
|
||||||
import org.gradle.api.file.ConfigurableFileCollection;
|
import org.gradle.api.file.ConfigurableFileCollection;
|
||||||
|
import org.gradle.api.file.FileCollection;
|
||||||
|
import org.gradle.api.tasks.SourceSet;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.configuration.InstallerData;
|
import net.fabricmc.loom.configuration.InstallerData;
|
||||||
|
@ -55,7 +54,7 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||||
private final LoomFiles loomFiles;
|
private final LoomFiles loomFiles;
|
||||||
private final ConfigurableFileCollection unmappedMods;
|
private final ConfigurableFileCollection unmappedMods;
|
||||||
|
|
||||||
private final Set<File> mixinMappings = Collections.synchronizedSet(new HashSet<>());
|
private final ConfigurableFileCollection mixinMappings;
|
||||||
private final MappingSet[] srcMappingCache = new MappingSet[2];
|
private final MappingSet[] srcMappingCache = new MappingSet[2];
|
||||||
private final Mercury[] srcMercuryCache = new Mercury[2];
|
private final Mercury[] srcMercuryCache = new Mercury[2];
|
||||||
private final Map<String, NamedDomainObjectProvider<Configuration>> lazyConfigurations = new HashMap<>();
|
private final Map<String, NamedDomainObjectProvider<Configuration>> lazyConfigurations = new HashMap<>();
|
||||||
|
@ -70,6 +69,7 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||||
this.project = project;
|
this.project = project;
|
||||||
// Initiate with newInstance to allow gradle to decorate our extension
|
// Initiate with newInstance to allow gradle to decorate our extension
|
||||||
this.mixinApExtension = project.getObjects().newInstance(MixinExtensionImpl.class, project);
|
this.mixinApExtension = project.getObjects().newInstance(MixinExtensionImpl.class, project);
|
||||||
|
this.mixinMappings = project.getObjects().fileCollection();
|
||||||
this.loomFiles = files;
|
this.loomFiles = files;
|
||||||
this.unmappedMods = project.files();
|
this.unmappedMods = project.files();
|
||||||
}
|
}
|
||||||
|
@ -85,15 +85,15 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized File getNextMixinMappings() {
|
public synchronized File getMixinMappings(SourceSet sourceSet) {
|
||||||
File mixinMapping = new File(getFiles().getProjectBuildCache(), "mixin-map-" + getMappingsProvider().mappingsIdentifier() + "." + mixinMappings.size() + ".tiny");
|
File mixinMapping = new File(getFiles().getProjectBuildCache(), "mixin-map-" + getMappingsProvider().mappingsIdentifier() + "." + sourceSet.getName() + ".tiny");
|
||||||
mixinMappings.add(mixinMapping);
|
mixinMappings.from(getProject().files(mixinMapping));
|
||||||
return mixinMapping;
|
return mixinMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<File> getAllMixinMappings() {
|
public FileCollection getAllMixinMappings() {
|
||||||
return mixinMappings;
|
return mixinMappings.filter(File::exists);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
123
src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java
Normal file
123
src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.task;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.gradle.api.Action;
|
||||||
|
import org.gradle.api.file.ConfigurableFileCollection;
|
||||||
|
import org.gradle.api.file.RegularFileProperty;
|
||||||
|
import org.gradle.api.provider.Property;
|
||||||
|
import org.gradle.api.tasks.Input;
|
||||||
|
import org.gradle.api.tasks.InputFile;
|
||||||
|
import org.gradle.api.tasks.InputFiles;
|
||||||
|
import org.gradle.jvm.tasks.Jar;
|
||||||
|
import org.gradle.workers.WorkAction;
|
||||||
|
import org.gradle.workers.WorkParameters;
|
||||||
|
import org.gradle.workers.WorkQueue;
|
||||||
|
import org.gradle.workers.WorkerExecutor;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||||
|
import net.fabricmc.loom.util.ZipReprocessorUtil;
|
||||||
|
|
||||||
|
public abstract class AbstractRemapJarTask extends Jar {
|
||||||
|
@InputFile
|
||||||
|
public abstract RegularFileProperty getInputFile();
|
||||||
|
|
||||||
|
@InputFiles
|
||||||
|
public abstract ConfigurableFileCollection getClasspath();
|
||||||
|
|
||||||
|
@Input
|
||||||
|
public abstract Property<String> getSourceNamespace();
|
||||||
|
|
||||||
|
@Input
|
||||||
|
public abstract Property<String> getTargetNamespace();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected abstract WorkerExecutor getWorkerExecutor();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public AbstractRemapJarTask() {
|
||||||
|
getSourceNamespace().convention(MappingsNamespace.NAMED.toString()).finalizeValueOnRead();
|
||||||
|
getTargetNamespace().convention(MappingsNamespace.INTERMEDIARY.toString()).finalizeValueOnRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final <P extends AbstractRemapParams> void submitWork(Class<? extends AbstractRemapAction<P>> workAction, Action<P> action) {
|
||||||
|
final WorkQueue workQueue = getWorkerExecutor().noIsolation();
|
||||||
|
|
||||||
|
workQueue.submit(workAction, params -> {
|
||||||
|
params.getInputFile().set(getInputFile());
|
||||||
|
params.getOutputFile().set(getArchiveFile());
|
||||||
|
|
||||||
|
params.getSourceNamespace().set(getSourceNamespace());
|
||||||
|
params.getTargetNamespace().set(getTargetNamespace());
|
||||||
|
|
||||||
|
params.getArchivePreserveFileTimestamps().set(isPreserveFileTimestamps());
|
||||||
|
params.getArchiveReproducibleFileOrder().set(isReproducibleFileOrder());
|
||||||
|
|
||||||
|
action.execute(params);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface AbstractRemapParams extends WorkParameters {
|
||||||
|
RegularFileProperty getInputFile();
|
||||||
|
RegularFileProperty getOutputFile();
|
||||||
|
|
||||||
|
Property<String> getSourceNamespace();
|
||||||
|
Property<String> getTargetNamespace();
|
||||||
|
|
||||||
|
Property<Boolean> getArchivePreserveFileTimestamps();
|
||||||
|
Property<Boolean> getArchiveReproducibleFileOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class AbstractRemapAction<T extends AbstractRemapParams> implements WorkAction<T> {
|
||||||
|
protected final Path inputFile;
|
||||||
|
protected final Path outputFile;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public AbstractRemapAction() {
|
||||||
|
inputFile = getParameters().getInputFile().getAsFile().get().toPath();
|
||||||
|
outputFile = getParameters().getOutputFile().getAsFile().get().toPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void rewriteJar() throws IOException {
|
||||||
|
final boolean isReproducibleFileOrder = getParameters().getArchiveReproducibleFileOrder().get();
|
||||||
|
final boolean isPreserveFileTimestamps = getParameters().getArchivePreserveFileTimestamps().get();
|
||||||
|
|
||||||
|
if (isReproducibleFileOrder || !isPreserveFileTimestamps) {
|
||||||
|
ZipReprocessorUtil.reprocessZip(outputFile.toFile(), isReproducibleFileOrder, isPreserveFileTimestamps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@InputFile
|
||||||
|
public RegularFileProperty getInput() {
|
||||||
|
return getInputFile();
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,17 +50,13 @@ public final class LoomTasks {
|
||||||
t.getOutputs().upToDateWhen(o -> false);
|
t.getOutputs().upToDateWhen(o -> false);
|
||||||
});
|
});
|
||||||
|
|
||||||
tasks.register("remapJar", RemapJarTask.class, t -> {
|
RemapTaskConfiguration.setupRemap(project);
|
||||||
t.setDescription("Remaps the built project jar to intermediary mappings.");
|
|
||||||
t.setGroup(Constants.TaskGroup.FABRIC);
|
|
||||||
});
|
|
||||||
|
|
||||||
TaskProvider<ExtractNativesTask> extractNatives = tasks.register("extractNatives", ExtractNativesTask.class);
|
TaskProvider<ExtractNativesTask> extractNatives = tasks.register("extractNatives", ExtractNativesTask.class);
|
||||||
tasks.register("downloadAssets", DownloadAssetsTask.class, t -> {
|
tasks.register("downloadAssets", DownloadAssetsTask.class, t -> {
|
||||||
t.dependsOn(extractNatives);
|
t.dependsOn(extractNatives);
|
||||||
t.setDescription("Downloads required assets for Fabric.");
|
t.setDescription("Downloads required assets for Fabric.");
|
||||||
});
|
});
|
||||||
tasks.register("remapSourcesJar", RemapSourcesJarTask.class, t -> t.setDescription("Remaps the project sources jar to intermediary names."));
|
|
||||||
|
|
||||||
TaskProvider<ValidateAccessWidenerTask> validateAccessWidener = tasks.register("validateAccessWidener", ValidateAccessWidenerTask.class, t -> {
|
TaskProvider<ValidateAccessWidenerTask> validateAccessWidener = tasks.register("validateAccessWidener", ValidateAccessWidenerTask.class, t -> {
|
||||||
t.setDescription("Validate all the rules in the access widener against the Minecraft jar");
|
t.setDescription("Validate all the rules in the access widener against the Minecraft jar");
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
|
||||||
*
|
|
||||||
* Copyright (c) 2016-2020 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.task;
|
|
||||||
|
|
||||||
import org.gradle.api.tasks.Internal;
|
|
||||||
|
|
||||||
import net.fabricmc.loom.util.SourceRemapper;
|
|
||||||
|
|
||||||
public class RemapAllSourcesTask extends AbstractLoomTask {
|
|
||||||
public SourceRemapper sourceRemapper;
|
|
||||||
|
|
||||||
@Internal
|
|
||||||
public SourceRemapper getSourceRemapper() {
|
|
||||||
return sourceRemapper;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016-2021 FabricMC
|
* Copyright (c) 2021 FabricMC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -27,276 +27,281 @@ package net.fabricmc.loom.task;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UncheckedIOException;
|
import java.io.Serializable;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.util.Collection;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Objects;
|
||||||
import java.util.jar.Manifest;
|
import java.util.jar.Manifest;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import org.gradle.api.Action;
|
import com.google.gson.JsonObject;
|
||||||
import org.gradle.api.Project;
|
|
||||||
import org.gradle.api.artifacts.Configuration;
|
import org.gradle.api.artifacts.Configuration;
|
||||||
|
import org.gradle.api.file.ConfigurableFileCollection;
|
||||||
import org.gradle.api.file.FileCollection;
|
import org.gradle.api.file.FileCollection;
|
||||||
import org.gradle.api.file.RegularFileProperty;
|
|
||||||
import org.gradle.api.plugins.JavaPlugin;
|
import org.gradle.api.plugins.JavaPlugin;
|
||||||
|
import org.gradle.api.provider.ListProperty;
|
||||||
import org.gradle.api.provider.Property;
|
import org.gradle.api.provider.Property;
|
||||||
|
import org.gradle.api.provider.Provider;
|
||||||
import org.gradle.api.tasks.Input;
|
import org.gradle.api.tasks.Input;
|
||||||
import org.gradle.api.tasks.InputFile;
|
import org.gradle.api.tasks.InputFiles;
|
||||||
|
import org.gradle.api.tasks.SourceSet;
|
||||||
import org.gradle.api.tasks.TaskAction;
|
import org.gradle.api.tasks.TaskAction;
|
||||||
import org.gradle.jvm.tasks.Jar;
|
import org.objectweb.asm.commons.Remapper;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import net.fabricmc.accesswidener.AccessWidenerReader;
|
||||||
|
import net.fabricmc.accesswidener.AccessWidenerRemapper;
|
||||||
|
import net.fabricmc.accesswidener.AccessWidenerWriter;
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||||
import net.fabricmc.loom.build.JarRemapper;
|
|
||||||
import net.fabricmc.loom.build.MixinRefmapHelper;
|
import net.fabricmc.loom.build.MixinRefmapHelper;
|
||||||
|
import net.fabricmc.loom.build.nesting.IncludedJarFactory;
|
||||||
import net.fabricmc.loom.build.nesting.JarNester;
|
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.NestedJarPathProvider;
|
|
||||||
import net.fabricmc.loom.build.nesting.NestedJarProvider;
|
|
||||||
import net.fabricmc.loom.configuration.JarManifestConfiguration;
|
|
||||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
||||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor;
|
import net.fabricmc.loom.extension.MixinExtension;
|
||||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
import net.fabricmc.loom.task.service.JarManifestService;
|
||||||
|
import net.fabricmc.loom.task.service.MappingsService;
|
||||||
import net.fabricmc.loom.util.Constants;
|
import net.fabricmc.loom.util.Constants;
|
||||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
|
||||||
import net.fabricmc.loom.util.ZipReprocessorUtil;
|
|
||||||
import net.fabricmc.loom.util.ZipUtils;
|
import net.fabricmc.loom.util.ZipUtils;
|
||||||
import net.fabricmc.stitch.util.Pair;
|
import net.fabricmc.tinyremapper.InputTag;
|
||||||
|
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;
|
||||||
import net.fabricmc.tinyremapper.extension.mixin.MixinExtension;
|
|
||||||
|
|
||||||
public class RemapJarTask extends Jar {
|
public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||||
private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
|
private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
|
||||||
|
|
||||||
private final RegularFileProperty input;
|
@InputFiles
|
||||||
private final Property<Boolean> addNestedDependencies;
|
public abstract ConfigurableFileCollection getNestedJars();
|
||||||
private final Property<Boolean> addDefaultNestedDependencies;
|
|
||||||
private final Property<Boolean> remapAccessWidener;
|
|
||||||
private final List<Action<TinyRemapper.Builder>> remapOptions = new ArrayList<>();
|
|
||||||
public JarRemapper jarRemapper;
|
|
||||||
private FileCollection classpath;
|
|
||||||
private final Set<Object> nestedPaths = new LinkedHashSet<>();
|
|
||||||
|
|
||||||
|
@Input
|
||||||
|
public abstract Property<Boolean> getAddNestedDependencies();
|
||||||
|
|
||||||
|
@Inject
|
||||||
public RemapJarTask() {
|
public RemapJarTask() {
|
||||||
super();
|
super();
|
||||||
LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
|
||||||
input = getProject().getObjects().fileProperty();
|
|
||||||
addNestedDependencies = getProject().getObjects().property(Boolean.class)
|
|
||||||
.convention(false);
|
|
||||||
addDefaultNestedDependencies = getProject().getObjects().property(Boolean.class)
|
|
||||||
.convention(true);
|
|
||||||
remapAccessWidener = getProject().getObjects().property(Boolean.class)
|
|
||||||
.convention(false);
|
|
||||||
|
|
||||||
if (!extension.getMixin().getUseLegacyMixinAp().get()) {
|
getClasspath().from(getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME));
|
||||||
remapOptions.add(b -> b.extension(new MixinExtension()));
|
getAddNestedDependencies().convention(true).finalizeValueOnRead();
|
||||||
}
|
|
||||||
|
Configuration includeConfiguration = getProject().getConfigurations().getByName(Constants.Configurations.INCLUDE);
|
||||||
|
getNestedJars().from(new IncludedJarFactory(getProject()).getNestedJars(includeConfiguration));
|
||||||
}
|
}
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
public void doTask() throws Throwable {
|
public void run() {
|
||||||
boolean singleRemap = false;
|
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
||||||
|
|
||||||
if (jarRemapper == null) {
|
submitWork(RemapAction.class, params -> {
|
||||||
singleRemap = true;
|
if (getAddNestedDependencies().get()) {
|
||||||
jarRemapper = new JarRemapper();
|
params.getNestedJars().from(getNestedJars());
|
||||||
|
}
|
||||||
|
|
||||||
|
params.getJarManifestService().set(JarManifestService.get(getProject()));
|
||||||
|
params.getRemapClasspath().from(getClasspath());
|
||||||
|
params.getMappings().add(MappingsService.createDefault(getProject(), getSourceNamespace().get(), getTargetNamespace().get()));
|
||||||
|
|
||||||
|
final boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get();
|
||||||
|
params.getUseMixinExtension().set(!legacyMixin);
|
||||||
|
|
||||||
|
if (legacyMixin) {
|
||||||
|
params.getMixinMappings().from(extension.getAllMixinMappings());
|
||||||
|
setupLegacyMixinRefmapRemapping(params);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupLegacyMixinRefmapRemapping(RemapParams params) {
|
||||||
|
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
||||||
|
final MixinExtension mixinExtension = extension.getMixin();
|
||||||
|
|
||||||
|
final JsonObject fabricModJson = MixinRefmapHelper.readFabricModJson(getInputFile().getAsFile().get());
|
||||||
|
|
||||||
|
if (fabricModJson == null) {
|
||||||
|
getProject().getLogger().warn("Could not find fabric.mod.json file in: " + getInputFile().getAsFile().get().getName());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduleRemap(singleRemap || LoomGradleExtension.get(getProject()).isRootProject());
|
final Collection<String> allMixinConfigs = MixinRefmapHelper.getMixinConfigurationFiles(fabricModJson);
|
||||||
|
|
||||||
if (singleRemap) {
|
for (SourceSet sourceSet : mixinExtension.getMixinSourceSets()) {
|
||||||
jarRemapper.remap();
|
MixinExtension.MixinInformationContainer container = Objects.requireNonNull(
|
||||||
|
MixinExtension.getMixinInformationContainer(sourceSet)
|
||||||
|
);
|
||||||
|
|
||||||
|
final String refmapName = container.refmapNameProvider().get();
|
||||||
|
final List<String> mixinConfigs = container.sourceSet().getResources()
|
||||||
|
.matching(container.mixinConfigPattern())
|
||||||
|
.getFiles()
|
||||||
|
.stream()
|
||||||
|
.map(File::getName)
|
||||||
|
.filter(allMixinConfigs::contains)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
params.getMixinData().add(new RemapParams.RefmapData(mixinConfigs, refmapName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void scheduleRemap(boolean isMainRemapTask) throws Throwable {
|
public interface RemapParams extends AbstractRemapParams {
|
||||||
Project project = getProject();
|
ConfigurableFileCollection getNestedJars();
|
||||||
LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
ConfigurableFileCollection getRemapClasspath();
|
||||||
Path input = this.getInput().getAsFile().get().toPath();
|
ConfigurableFileCollection getMixinMappings();
|
||||||
Path output = this.getArchiveFile().get().getAsFile().toPath();
|
ListProperty<Provider<MappingsService>> getMappings();
|
||||||
|
|
||||||
if (!Files.exists(input)) {
|
Property<Boolean> getUseMixinExtension();
|
||||||
throw new FileNotFoundException(input.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
|
record RefmapData(List<String> mixinConfigs, String refmapName) implements Serializable { }
|
||||||
|
ListProperty<RefmapData> getMixinData();
|
||||||
|
|
||||||
String fromM = MappingsNamespace.NAMED.toString();
|
Property<JarManifestService> getJarManifestService();
|
||||||
String toM = MappingsNamespace.INTERMEDIARY.toString();
|
}
|
||||||
|
|
||||||
if (isMainRemapTask) {
|
public abstract static class RemapAction extends AbstractRemapAction<RemapParams> {
|
||||||
jarRemapper.addToClasspath(getRemapClasspath());
|
private static final Logger LOGGER = LoggerFactory.getLogger(RemapAction.class);
|
||||||
|
|
||||||
jarRemapper.addMappings(TinyRemapperHelper.create(mappingsProvider.getMappings(), fromM, toM, false));
|
private TinyRemapper tinyRemapper;
|
||||||
}
|
|
||||||
|
|
||||||
for (File mixinMapFile : extension.getAllMixinMappings()) {
|
@Override
|
||||||
if (mixinMapFile.exists()) {
|
public void execute() {
|
||||||
jarRemapper.addMappings(TinyUtils.createTinyMappingProvider(mixinMapFile.toPath(), fromM, toM));
|
try {
|
||||||
|
LOGGER.info("Remapping {} to {}", inputFile, outputFile);
|
||||||
|
|
||||||
|
tinyRemapper = createTinyRemapper();
|
||||||
|
|
||||||
|
remap();
|
||||||
|
remapAccessWidener();
|
||||||
|
addRefmaps();
|
||||||
|
addNestedJars();
|
||||||
|
modifyJarManifest();
|
||||||
|
rewriteJar();
|
||||||
|
|
||||||
|
tinyRemapper.finish();
|
||||||
|
tinyRemapper = null;
|
||||||
|
|
||||||
|
LOGGER.debug("Finished remapping {}", inputFile);
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(outputFile);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.error("Failed to delete output file", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeException("Failed to remap", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add remap options to the jar remapper
|
private void remap() throws IOException {
|
||||||
jarRemapper.addOptions(this.remapOptions);
|
final InputTag inputTag = tinyRemapper.createInputTag();
|
||||||
|
|
||||||
NestedJarProvider nestedJarProvider = getNestedJarProvider();
|
tinyRemapper.readInputsAsync(inputTag, inputFile);
|
||||||
nestedJarProvider.prepare(getProject());
|
|
||||||
|
|
||||||
jarRemapper.scheduleRemap(input, output)
|
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(outputFile).build()) {
|
||||||
.supplyAccessWidener((remapData, remapper) -> {
|
outputConsumer.addNonClassFiles(inputFile);
|
||||||
if (getRemapAccessWidener().getOrElse(false) && extension.getAccessWidenerPath().isPresent()) {
|
tinyRemapper.apply(outputConsumer, inputTag);
|
||||||
AccessWidenerJarProcessor accessWidenerJarProcessor = extension.getJarProcessorManager().getByType(AccessWidenerJarProcessor.class);
|
}
|
||||||
byte[] data;
|
|
||||||
|
|
||||||
try {
|
|
||||||
data = accessWidenerJarProcessor.getRemappedAccessWidener(remapper, toM);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Failed to remap access widener", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
AccessWidenerFile awFile = AccessWidenerFile.fromModJar(remapData.input);
|
|
||||||
Preconditions.checkNotNull(awFile, "Failed to find accessWidener in fabric.mod.json: " + remapData.input);
|
|
||||||
|
|
||||||
return Pair.of(awFile.name(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
.complete((data, accessWidener) -> {
|
|
||||||
if (!Files.exists(output)) {
|
|
||||||
throw new RuntimeException("Failed to remap " + input + " to " + output + " - file missing!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extension.getMixin().getUseLegacyMixinAp().get()) {
|
|
||||||
if (MixinRefmapHelper.addRefmapName(project, output)) {
|
|
||||||
project.getLogger().debug("Transformed mixin reference maps in output JAR!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getAddNestedDependencies().getOrElse(false)) {
|
|
||||||
JarNester.nestJars(nestedJarProvider.provide(), output.toFile(), project.getLogger());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accessWidener != null) {
|
|
||||||
try {
|
|
||||||
ZipUtils.replace(data.output, accessWidener.getLeft(), accessWidener.getRight());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new UncheckedIOException("Failed to replace access widener in output jar", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add data to the manifest
|
|
||||||
try {
|
|
||||||
int count = ZipUtils.transform(data.output, Map.of(MANIFEST_PATH, bytes -> {
|
|
||||||
var manifest = new Manifest(new ByteArrayInputStream(bytes));
|
|
||||||
var manifestConfiguration = new JarManifestConfiguration(project);
|
|
||||||
|
|
||||||
manifestConfiguration.configure(manifest);
|
|
||||||
manifest.getMainAttributes().putValue("Fabric-Mapping-Namespace", toM);
|
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
||||||
manifest.write(out);
|
|
||||||
return out.toByteArray();
|
|
||||||
}));
|
|
||||||
|
|
||||||
Preconditions.checkState(count > 0, "Did not transform any jar manifest");
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new UncheckedIOException("Failed to transform jar manifest", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isReproducibleFileOrder() || !isPreserveFileTimestamps()) {
|
|
||||||
try {
|
|
||||||
ZipReprocessorUtil.reprocessZip(output.toFile(), isReproducibleFileOrder(), isPreserveFileTimestamps());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Failed to re-process jar", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
private void remapAccessWidener() throws IOException {
|
||||||
|
final AccessWidenerFile accessWidenerFile = AccessWidenerFile.fromModJar(inputFile);
|
||||||
|
|
||||||
if (nestedPaths.isEmpty()) {
|
if (accessWidenerFile == null) {
|
||||||
return baseProvider;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] remapped = remapAccessWidener(accessWidenerFile.content(), tinyRemapper.getEnvironment().getRemapper(), MappingsNamespace.INTERMEDIARY.toString());
|
||||||
|
|
||||||
|
// Finally, replace the output with the remaped aw
|
||||||
|
ZipUtils.replace(outputFile, accessWidenerFile.path(), remapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MergedNestedJarProvider(
|
private static byte[] remapAccessWidener(byte[] input, Remapper asmRemapper, String targetNamespace) {
|
||||||
baseProvider,
|
int version = AccessWidenerReader.readVersion(input);
|
||||||
new NestedJarPathProvider(nestedPaths)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path[] getRemapClasspath() {
|
AccessWidenerWriter writer = new AccessWidenerWriter(version);
|
||||||
FileCollection files = this.classpath;
|
AccessWidenerRemapper remapper = new AccessWidenerRemapper(
|
||||||
|
writer,
|
||||||
|
asmRemapper,
|
||||||
|
MappingsNamespace.NAMED.toString(),
|
||||||
|
targetNamespace
|
||||||
|
);
|
||||||
|
AccessWidenerReader reader = new AccessWidenerReader(remapper);
|
||||||
|
reader.read(input);
|
||||||
|
|
||||||
if (files == null) {
|
return writer.write();
|
||||||
files = getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return files.getFiles().stream()
|
private void addNestedJars() {
|
||||||
.map(File::toPath)
|
FileCollection nestedJars = getParameters().getNestedJars();
|
||||||
.filter(Files::exists)
|
|
||||||
.toArray(Path[]::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
@InputFile
|
if (nestedJars.isEmpty()) {
|
||||||
public RegularFileProperty getInput() {
|
LOGGER.info("No jars to nest");
|
||||||
return input;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input
|
JarNester.nestJars(nestedJars.getFiles(), outputFile.toFile(), LOGGER);
|
||||||
public Property<Boolean> getAddNestedDependencies() {
|
|
||||||
return addNestedDependencies;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Input
|
|
||||||
public Property<Boolean> getAddDefaultNestedDependencies() {
|
|
||||||
return addDefaultNestedDependencies;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Input
|
|
||||||
public Property<Boolean> getRemapAccessWidener() {
|
|
||||||
return remapAccessWidener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remapOptions(Action<TinyRemapper.Builder> action) {
|
|
||||||
this.remapOptions.add(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RemapJarTask classpath(FileCollection collection) {
|
|
||||||
if (this.classpath == null) {
|
|
||||||
this.classpath = collection;
|
|
||||||
} else {
|
|
||||||
this.classpath = this.classpath.plus(collection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
private void modifyJarManifest() throws IOException {
|
||||||
}
|
int count = ZipUtils.transform(outputFile, Map.of(MANIFEST_PATH, bytes -> {
|
||||||
|
var manifest = new Manifest(new ByteArrayInputStream(bytes));
|
||||||
|
|
||||||
@ApiStatus.Experimental
|
getParameters().getJarManifestService().get().apply(manifest);
|
||||||
// This only allows mod jars, proceed with care when trying to pass in configurations with projects, or something that depends on a task.
|
manifest.getMainAttributes().putValue("Fabric-Mapping-Namespace", getParameters().getTargetNamespace().get());
|
||||||
public RemapJarTask include(Object... paths) {
|
|
||||||
Collections.addAll(nestedPaths, paths);
|
|
||||||
this.addNestedDependencies.set(true);
|
|
||||||
|
|
||||||
return this;
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
manifest.write(out);
|
||||||
|
return out.toByteArray();
|
||||||
|
}));
|
||||||
|
|
||||||
|
Preconditions.checkState(count > 0, "Did not transform any jar manifest");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRefmaps() throws IOException {
|
||||||
|
if (getParameters().getUseMixinExtension().get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (RemapParams.RefmapData refmapData : getParameters().getMixinData().get()) {
|
||||||
|
int transformed = ZipUtils.transformJson(JsonObject.class, outputFile, refmapData.mixinConfigs().stream().collect(Collectors.toMap(s -> s, s -> json -> {
|
||||||
|
if (!json.has("refmap")) {
|
||||||
|
json.addProperty("refmap", refmapData.refmapName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return json;
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TinyRemapper createTinyRemapper() {
|
||||||
|
TinyRemapper.Builder builder = TinyRemapper.newRemapper();
|
||||||
|
|
||||||
|
for (Provider<MappingsService> provider : getParameters().getMappings().get()) {
|
||||||
|
builder.withMappings(provider.get().getMappingsProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (File mixinMapping : getParameters().getMixinMappings()) {
|
||||||
|
builder.withMappings(TinyUtils.createTinyMappingProvider(mixinMapping.toPath(), getParameters().getSourceNamespace().get(), getParameters().getTargetNamespace().get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getParameters().getUseMixinExtension().get()) {
|
||||||
|
builder.extension(new net.fabricmc.tinyremapper.extension.mixin.MixinExtension());
|
||||||
|
}
|
||||||
|
|
||||||
|
TinyRemapper remapper = builder.build();
|
||||||
|
|
||||||
|
// Apply classpath
|
||||||
|
for (File file : getParameters().getRemapClasspath()) {
|
||||||
|
remapper.readClassPathAsync(file.toPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
return remapper;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016-2021 FabricMC
|
* Copyright (c) 2021 FabricMC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -24,70 +24,65 @@
|
||||||
|
|
||||||
package net.fabricmc.loom.task;
|
package net.fabricmc.loom.task;
|
||||||
|
|
||||||
import org.gradle.api.file.RegularFileProperty;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.gradle.api.plugins.JavaPlugin;
|
||||||
import org.gradle.api.provider.Property;
|
import org.gradle.api.provider.Property;
|
||||||
import org.gradle.api.tasks.Input;
|
|
||||||
import org.gradle.api.tasks.InputFile;
|
|
||||||
import org.gradle.api.tasks.Internal;
|
|
||||||
import org.gradle.api.tasks.OutputFile;
|
|
||||||
import org.gradle.api.tasks.TaskAction;
|
import org.gradle.api.tasks.TaskAction;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
import net.fabricmc.loom.task.service.MappingsService;
|
||||||
import net.fabricmc.loom.util.SourceRemapper;
|
import net.fabricmc.loom.task.service.SourceRemapperService;
|
||||||
|
|
||||||
public class RemapSourcesJarTask extends AbstractLoomTask {
|
|
||||||
private final RegularFileProperty input = getProject().getObjects().fileProperty();
|
|
||||||
private final RegularFileProperty output = getProject().getObjects().fileProperty().convention(input);
|
|
||||||
private final Property<String> targetNamespace = getProject().getObjects().property(String.class).convention(MappingsNamespace.INTERMEDIARY.toString());
|
|
||||||
private SourceRemapper sourceRemapper = null;
|
|
||||||
private final Property<Boolean> preserveFileTimestamps = getProject().getObjects().property(Boolean.class).convention(true);
|
|
||||||
private final Property<Boolean> reproducibleFileOrder = getProject().getObjects().property(Boolean.class).convention(false);
|
|
||||||
|
|
||||||
|
public abstract class RemapSourcesJarTask extends AbstractRemapJarTask {
|
||||||
|
@Inject
|
||||||
public RemapSourcesJarTask() {
|
public RemapSourcesJarTask() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
getClasspath().from(getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
public void remap() throws Exception {
|
public void run() {
|
||||||
if (sourceRemapper == null) {
|
submitWork(RemapSourcesAction.class, params -> {
|
||||||
String direction = targetNamespace.get();
|
params.getSourcesRemapperService().set(SourceRemapperService.create(getProject(), MappingsService.createDefault(getProject(), getSourceNamespace().get(), getTargetNamespace().get()), getClasspath()));
|
||||||
SourceRemapper.remapSources(getProject(), input.get().getAsFile(), output.get().getAsFile(), direction.equals(MappingsNamespace.NAMED.toString()), reproducibleFileOrder.get(), preserveFileTimestamps.get());
|
});
|
||||||
} else {
|
}
|
||||||
sourceRemapper.scheduleRemapSources(input.get().getAsFile(), output.get().getAsFile(), reproducibleFileOrder.get(), preserveFileTimestamps.get());
|
|
||||||
|
public interface RemapSourcesParams extends AbstractRemapParams {
|
||||||
|
Property<SourceRemapperService> getSourcesRemapperService();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class RemapSourcesAction extends AbstractRemapAction<RemapSourcesParams> {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(RemapSourcesAction.class);
|
||||||
|
|
||||||
|
private final SourceRemapperService sourceRemapperService;
|
||||||
|
|
||||||
|
public RemapSourcesAction() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
sourceRemapperService = getParameters().getSourcesRemapperService().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
try {
|
||||||
|
sourceRemapperService.remapSourcesJar(inputFile, outputFile);
|
||||||
|
|
||||||
|
rewriteJar();
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
Files.deleteIfExists(outputFile);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOGGER.error("Failed to delete output file", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeException("Failed to remap sources", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Internal
|
|
||||||
public SourceRemapper getSourceRemapper() {
|
|
||||||
return sourceRemapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RemapSourcesJarTask setSourceRemapper(SourceRemapper sourceRemapper) {
|
|
||||||
this.sourceRemapper = sourceRemapper;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@InputFile
|
|
||||||
public RegularFileProperty getInput() {
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
@OutputFile
|
|
||||||
public RegularFileProperty getOutput() {
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Input
|
|
||||||
public Property<String> getTargetNamespace() {
|
|
||||||
return targetNamespace;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Input
|
|
||||||
public Property<Boolean> getPreserveFileTimestamps() {
|
|
||||||
return preserveFileTimestamps;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Input
|
|
||||||
public Property<Boolean> getReproducibleFileOrder() {
|
|
||||||
return reproducibleFileOrder;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
138
src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java
Normal file
138
src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016-2021 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.task;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.Task;
|
||||||
|
import org.gradle.api.artifacts.Configuration;
|
||||||
|
import org.gradle.api.plugins.BasePlugin;
|
||||||
|
import org.gradle.api.plugins.JavaPlugin;
|
||||||
|
import org.gradle.api.plugins.JavaPluginExtension;
|
||||||
|
import org.gradle.api.tasks.SourceSet;
|
||||||
|
import org.gradle.api.tasks.TaskContainer;
|
||||||
|
import org.gradle.api.tasks.TaskProvider;
|
||||||
|
import org.gradle.api.tasks.bundling.AbstractArchiveTask;
|
||||||
|
import org.gradle.api.tasks.bundling.Jar;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
|
import net.fabricmc.loom.util.Constants;
|
||||||
|
|
||||||
|
public class RemapTaskConfiguration {
|
||||||
|
public static final String REMAP_JAR_TASK_NAME = "remapJar";
|
||||||
|
public static final String REMAP_SOURCES_JAR_TASK_NAME = "remapSourcesJar";
|
||||||
|
|
||||||
|
public static void setupRemap(Project project) {
|
||||||
|
final TaskContainer tasks = project.getTasks();
|
||||||
|
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||||
|
|
||||||
|
if (!extension.getRemapArchives().get()) {
|
||||||
|
extension.getUnmappedModCollection().from(project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the default remap jar task
|
||||||
|
TaskProvider<RemapJarTask> remapJarTaskProvider = tasks.register(REMAP_JAR_TASK_NAME, RemapJarTask.class, task -> {
|
||||||
|
final AbstractArchiveTask jarTask = tasks.named(JavaPlugin.JAR_TASK_NAME, AbstractArchiveTask.class).get();
|
||||||
|
|
||||||
|
// Basic task setup
|
||||||
|
task.dependsOn(jarTask);
|
||||||
|
task.setDescription("Remaps the built project jar to intermediary mappings.");
|
||||||
|
task.setGroup(Constants.TaskGroup.FABRIC);
|
||||||
|
project.getArtifacts().add(JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, task);
|
||||||
|
project.getArtifacts().add(JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME, task);
|
||||||
|
|
||||||
|
// Setup the input file and the nested deps
|
||||||
|
task.getInputFile().convention(jarTask.getArchiveFile());
|
||||||
|
task.dependsOn(tasks.named(JavaPlugin.JAR_TASK_NAME));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configure the default jar task
|
||||||
|
tasks.named(JavaPlugin.JAR_TASK_NAME, AbstractArchiveTask.class).configure(task -> {
|
||||||
|
task.getArchiveClassifier().convention("dev");
|
||||||
|
task.getDestinationDirectory().set(new File(project.getBuildDir(), "devlibs"));
|
||||||
|
});
|
||||||
|
|
||||||
|
tasks.named(BasePlugin.ASSEMBLE_TASK_NAME).configure(task -> task.dependsOn(remapJarTaskProvider));
|
||||||
|
|
||||||
|
trySetupSourceRemapping(project);
|
||||||
|
|
||||||
|
if (extension.getSetupRemappedVariants().get()) {
|
||||||
|
// Remove -dev jars from the default jar task
|
||||||
|
for (String configurationName : new String[] { JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME }) {
|
||||||
|
Configuration configuration = project.getConfigurations().getByName(configurationName);
|
||||||
|
configuration.getArtifacts().removeIf(artifact -> {
|
||||||
|
Task jarTask = project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME);
|
||||||
|
// if the artifact is a -dev jar and "builtBy jar"
|
||||||
|
return "dev".equals(artifact.getClassifier()) && artifact.getBuildDependencies().getDependencies(null).contains(jarTask);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void trySetupSourceRemapping(Project project) {
|
||||||
|
final TaskContainer tasks = project.getTasks();
|
||||||
|
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||||
|
|
||||||
|
TaskProvider<RemapSourcesJarTask> remapSourcesTask = tasks.register(REMAP_SOURCES_JAR_TASK_NAME, RemapSourcesJarTask.class, task -> {
|
||||||
|
task.setDescription("Remaps the default sources jar to intermediary mappings.");
|
||||||
|
task.setGroup(Constants.TaskGroup.FABRIC);
|
||||||
|
|
||||||
|
final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
|
||||||
|
final String sourcesJarTaskName = javaExtension.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME).getSourcesJarTaskName();
|
||||||
|
final Task sourcesTask = project.getTasks().findByName(sourcesJarTaskName);
|
||||||
|
|
||||||
|
if (sourcesTask == null) {
|
||||||
|
project.getLogger().info("{} task was not found, not remapping sources", sourcesJarTaskName);
|
||||||
|
task.setEnabled(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(sourcesTask instanceof Jar sourcesJarTask)) {
|
||||||
|
project.getLogger().info("{} task is not a Jar task, not remapping sources", sourcesJarTaskName);
|
||||||
|
task.setEnabled(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcesJarTask.getArchiveClassifier().convention("dev-sources");
|
||||||
|
sourcesJarTask.getDestinationDirectory().set(new File(project.getBuildDir(), "devlibs"));
|
||||||
|
task.getArchiveClassifier().convention("sources");
|
||||||
|
|
||||||
|
task.dependsOn(sourcesJarTask);
|
||||||
|
task.getInputFile().convention(sourcesJarTask.getArchiveFile());
|
||||||
|
|
||||||
|
if (extension.getSetupRemappedVariants().get()) {
|
||||||
|
project.getArtifacts().add(JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME, task);
|
||||||
|
|
||||||
|
// Remove the dev sources artifact
|
||||||
|
Configuration configuration = project.getConfigurations().getByName(JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME);
|
||||||
|
configuration.getArtifacts().removeIf(a -> a.getFile().equals(sourcesJarTask.getArchiveFile().get().getAsFile()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tasks.named(BasePlugin.ASSEMBLE_TASK_NAME).configure(task -> task.dependsOn(remapSourcesTask));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.task.service;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.jar.Attributes;
|
||||||
|
import java.util.jar.Manifest;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.artifacts.Dependency;
|
||||||
|
import org.gradle.api.provider.Property;
|
||||||
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.gradle.api.services.BuildService;
|
||||||
|
import org.gradle.api.services.BuildServiceParameters;
|
||||||
|
import org.gradle.util.GradleVersion;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
|
import net.fabricmc.loom.LoomGradlePlugin;
|
||||||
|
import net.fabricmc.loom.util.Constants;
|
||||||
|
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||||
|
|
||||||
|
public abstract class JarManifestService implements BuildService<JarManifestService.Params> {
|
||||||
|
interface Params extends BuildServiceParameters {
|
||||||
|
Property<String> getGradleVersion();
|
||||||
|
Property<String> getLoomVersion();
|
||||||
|
Property<String> getMCEVersion();
|
||||||
|
Property<String> getMinecraftVersion();
|
||||||
|
Property<String> getTinyRemapperVersion();
|
||||||
|
Property<String> getFabricLoaderVersion();
|
||||||
|
Property<MixinVersion> getMixinVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Provider<JarManifestService> get(Project project) {
|
||||||
|
return project.getGradle().getSharedServices().registerIfAbsent("LoomJarManifestService:" + project.getName(), JarManifestService.class, spec -> {
|
||||||
|
spec.parameters(params -> {
|
||||||
|
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||||
|
Optional<String> tinyRemapperVersion = Optional.ofNullable(TinyRemapper.class.getPackage().getImplementationVersion());
|
||||||
|
|
||||||
|
params.getGradleVersion().set(GradleVersion.current().getVersion());
|
||||||
|
params.getLoomVersion().set(LoomGradlePlugin.LOOM_VERSION);
|
||||||
|
params.getMCEVersion().set(Constants.Dependencies.Versions.MIXIN_COMPILE_EXTENSIONS);
|
||||||
|
params.getMinecraftVersion().set(extension.getMinecraftProvider().minecraftVersion());
|
||||||
|
params.getTinyRemapperVersion().set(tinyRemapperVersion.orElse("unknown"));
|
||||||
|
params.getFabricLoaderVersion().set(getLoaderVersion(project).orElse("unknown"));
|
||||||
|
params.getMixinVersion().set(getMixinVersion(project).orElse(new MixinVersion("unknown", "unknown")));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void apply(Manifest manifest) {
|
||||||
|
// Don't set when running the reproducible build tests as it will break them when anything updates
|
||||||
|
if (Boolean.getBoolean("loom.test.reproducible")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Attributes attributes = manifest.getMainAttributes();
|
||||||
|
Params p = getParameters();
|
||||||
|
|
||||||
|
attributes.putValue("Fabric-Gradle-Version", p.getGradleVersion().get());
|
||||||
|
attributes.putValue("Fabric-Loom-Version", p.getLoomVersion().get());
|
||||||
|
attributes.putValue("Fabric-Mixin-Compile-Extensions-Version", p.getMCEVersion().get());
|
||||||
|
attributes.putValue("Fabric-Minecraft-Version", p.getMinecraftVersion().get());
|
||||||
|
attributes.putValue("Fabric-Tiny-Remapper-Version", p.getTinyRemapperVersion().get());
|
||||||
|
attributes.putValue("Fabric-Loader-Version", p.getFabricLoaderVersion().get());
|
||||||
|
|
||||||
|
// This can be overridden by mods if required
|
||||||
|
if (!attributes.containsKey("Fabric-Mixin-Version")) {
|
||||||
|
attributes.putValue("Fabric-Mixin-Version", p.getMixinVersion().get().version());
|
||||||
|
attributes.putValue("Fabric-Mixin-Group", p.getMixinVersion().get().group());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<String> getLoaderVersion(Project project) {
|
||||||
|
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||||
|
|
||||||
|
if (extension.getInstallerData() == null) {
|
||||||
|
project.getLogger().warn("Could not determine fabric loader version for jar manifest");
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.of(extension.getInstallerData().version());
|
||||||
|
}
|
||||||
|
|
||||||
|
private record MixinVersion(String group, String version) implements Serializable { }
|
||||||
|
|
||||||
|
private static Optional<MixinVersion> getMixinVersion(Project project) {
|
||||||
|
// Not super ideal that this uses the mod compile classpath, should prob look into making this not a thing at somepoint
|
||||||
|
Optional<Dependency> dependency = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES)
|
||||||
|
.getDependencies()
|
||||||
|
.stream()
|
||||||
|
.filter(dep -> "sponge-mixin".equals(dep.getName()))
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (dependency.isEmpty()) {
|
||||||
|
project.getLogger().warn("Could not determine Mixin version for jar manifest");
|
||||||
|
}
|
||||||
|
|
||||||
|
return dependency.map(d -> new MixinVersion(d.getGroup(), d.getVersion()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.task.service;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.file.RegularFileProperty;
|
||||||
|
import org.gradle.api.provider.Property;
|
||||||
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.gradle.api.services.BuildService;
|
||||||
|
import org.gradle.api.services.BuildServiceParameters;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
|
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||||
|
import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||||
|
import net.fabricmc.mappingio.MappingReader;
|
||||||
|
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||||
|
import net.fabricmc.tinyremapper.IMappingProvider;
|
||||||
|
|
||||||
|
public abstract class MappingsService implements BuildService<MappingsService.Params>, AutoCloseable {
|
||||||
|
interface Params extends BuildServiceParameters {
|
||||||
|
RegularFileProperty getMappingsFile();
|
||||||
|
|
||||||
|
Property<String> getFromNamespace();
|
||||||
|
Property<String> getToNamespace();
|
||||||
|
|
||||||
|
Property<Boolean> getRemapLocals();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized Provider<MappingsService> create(Project project, String name, File mappingsFile, String from, String to, boolean remapLocals) {
|
||||||
|
return project.getGradle().getSharedServices().registerIfAbsent(name, MappingsService.class, spec -> {
|
||||||
|
spec.parameters(params -> {
|
||||||
|
params.getMappingsFile().set(mappingsFile);
|
||||||
|
params.getFromNamespace().set(from);
|
||||||
|
params.getToNamespace().set(to);
|
||||||
|
params.getRemapLocals().set(remapLocals);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Provider<MappingsService> createDefault(Project project, String from, String to) {
|
||||||
|
final MappingsProviderImpl mappingsProvider = LoomGradleExtension.get(project).getMappingsProvider();
|
||||||
|
final String name = mappingsProvider.getBuildServiceName("mappingsProvider", from, to);
|
||||||
|
return MappingsService.create(project, name, mappingsProvider.tinyMappings.toFile(), from, to, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IMappingProvider mappingProvider = null;
|
||||||
|
private MemoryMappingTree memoryMappingTree = null;
|
||||||
|
|
||||||
|
public synchronized IMappingProvider getMappingsProvider() {
|
||||||
|
if (mappingProvider == null) {
|
||||||
|
try {
|
||||||
|
mappingProvider = TinyRemapperHelper.create(
|
||||||
|
getParameters().getMappingsFile().get().getAsFile().toPath(),
|
||||||
|
getParameters().getFromNamespace().get(),
|
||||||
|
getParameters().getToNamespace().get(),
|
||||||
|
getParameters().getRemapLocals().get()
|
||||||
|
);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException("Failed to read mappings from: " + getParameters().getMappingsFile().get().getAsFile().getAbsolutePath(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mappingProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized MemoryMappingTree getMemoryMappingTree() {
|
||||||
|
if (memoryMappingTree == null) {
|
||||||
|
memoryMappingTree = new MemoryMappingTree();
|
||||||
|
|
||||||
|
try {
|
||||||
|
MappingReader.read(getParameters().getMappingsFile().get().getAsFile().toPath(), memoryMappingTree);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException("Failed to read mappings from: " + getParameters().getMappingsFile().get().getAsFile().getAbsolutePath(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return memoryMappingTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFromNamespace() {
|
||||||
|
return getParameters().getFromNamespace().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToNamespace() {
|
||||||
|
return getParameters().getToNamespace().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
mappingProvider = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 FabricMC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.loom.task.service;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import org.cadixdev.lorenz.MappingSet;
|
||||||
|
import org.cadixdev.mercury.Mercury;
|
||||||
|
import org.cadixdev.mercury.remapper.MercuryRemapper;
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.file.ConfigurableFileCollection;
|
||||||
|
import org.gradle.api.file.FileCollection;
|
||||||
|
import org.gradle.api.provider.Property;
|
||||||
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.gradle.api.services.BuildService;
|
||||||
|
import org.gradle.api.services.BuildServiceParameters;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import net.fabricmc.loom.util.DeletingFileVisitor;
|
||||||
|
import net.fabricmc.loom.util.FileSystemUtil;
|
||||||
|
import net.fabricmc.loom.util.SourceRemapper;
|
||||||
|
import net.fabricmc.loom.util.ZipUtils;
|
||||||
|
import net.fabricmc.lorenztiny.TinyMappingsReader;
|
||||||
|
|
||||||
|
public abstract class SourceRemapperService implements BuildService<SourceRemapperService.Params>, AutoCloseable {
|
||||||
|
public interface Params extends BuildServiceParameters {
|
||||||
|
Property<Provider<MappingsService>> getMappings();
|
||||||
|
|
||||||
|
ConfigurableFileCollection getClasspath();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized Provider<SourceRemapperService> create(Project project, Provider<MappingsService> mappings, FileCollection classpath) {
|
||||||
|
// TODO may need a better name, im not too sure
|
||||||
|
return project.getGradle().getSharedServices().registerIfAbsent("sourceremapper", SourceRemapperService.class, spec ->
|
||||||
|
spec.parameters(params -> {
|
||||||
|
params.getMappings().set(mappings);
|
||||||
|
params.getClasspath().from(classpath);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(SourceRemapperService.class);
|
||||||
|
|
||||||
|
private Mercury mercury;
|
||||||
|
|
||||||
|
public void remapSourcesJar(Path source, Path destination) throws IOException {
|
||||||
|
if (source.equals(destination)) {
|
||||||
|
throw new UnsupportedOperationException("Cannot remap in place");
|
||||||
|
}
|
||||||
|
|
||||||
|
Path srcPath = source;
|
||||||
|
boolean isSrcTmp = false;
|
||||||
|
|
||||||
|
// Create a temp directory with all of the sources
|
||||||
|
if (!Files.isDirectory(source)) {
|
||||||
|
isSrcTmp = true;
|
||||||
|
srcPath = Files.createTempDirectory("fabric-loom-src");
|
||||||
|
ZipUtils.unpackAll(source, srcPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Files.isDirectory(destination) && Files.exists(destination)) {
|
||||||
|
Files.delete(destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
try (FileSystemUtil.Delegate dstFs = Files.isDirectory(destination) ? null : FileSystemUtil.getJarFileSystem(destination, true)) {
|
||||||
|
Path dstPath = dstFs != null ? dstFs.get().getPath("/") : destination;
|
||||||
|
|
||||||
|
doRemap(srcPath, dstPath, source);
|
||||||
|
SourceRemapper.copyNonJavaFiles(srcPath, dstPath, LOGGER, source);
|
||||||
|
} finally {
|
||||||
|
if (isSrcTmp) {
|
||||||
|
Files.walkFileTree(srcPath, new DeletingFileVisitor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void doRemap(Path srcPath, Path dstPath, Path source) throws IOException {
|
||||||
|
if (mercury == null) {
|
||||||
|
mercury = new Mercury();
|
||||||
|
mercury.setGracefulClasspathChecks(true);
|
||||||
|
mercury.getProcessors().add(MercuryRemapper.create(getMappings()));
|
||||||
|
|
||||||
|
getParameters().getClasspath().forEach(file -> mercury.getClassPath().add(file.toPath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Not thread safe!!
|
||||||
|
mercury.rewrite(srcPath, dstPath);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.warn("Could not remap " + source + " fully!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MappingSet getMappings() throws IOException {
|
||||||
|
return new TinyMappingsReader(mappingsService().getMemoryMappingTree(), mappingsService().getFromNamespace(), mappingsService().getToNamespace()).read();
|
||||||
|
}
|
||||||
|
|
||||||
|
private MappingsService mappingsService() {
|
||||||
|
return getParameters().getMappings().get().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws Exception {
|
||||||
|
mercury = null;
|
||||||
|
// This is required (:
|
||||||
|
System.gc();
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,6 +37,7 @@ import org.cadixdev.lorenz.MappingSet;
|
||||||
import org.cadixdev.mercury.Mercury;
|
import org.cadixdev.mercury.Mercury;
|
||||||
import org.cadixdev.mercury.remapper.MercuryRemapper;
|
import org.cadixdev.mercury.remapper.MercuryRemapper;
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||||
|
@ -142,7 +143,7 @@ public class SourceRemapper {
|
||||||
project.getLogger().warn("Could not remap " + source.getName() + " fully!", e);
|
project.getLogger().warn("Could not remap " + source.getName() + " fully!", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
copyNonJavaFiles(srcPath, dstPath, project, source);
|
copyNonJavaFiles(srcPath, dstPath, project.getLogger(), source.toPath());
|
||||||
|
|
||||||
if (dstFs != null) {
|
if (dstFs != null) {
|
||||||
dstFs.close();
|
dstFs.close();
|
||||||
|
@ -202,7 +203,7 @@ public class SourceRemapper {
|
||||||
return mercury;
|
return mercury;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void copyNonJavaFiles(Path from, Path to, Project project, File source) throws IOException {
|
public static void copyNonJavaFiles(Path from, Path to, Logger logger, Path source) throws IOException {
|
||||||
Files.walk(from).forEach(path -> {
|
Files.walk(from).forEach(path -> {
|
||||||
Path targetPath = to.resolve(from.relativize(path).toString());
|
Path targetPath = to.resolve(from.relativize(path).toString());
|
||||||
|
|
||||||
|
@ -210,7 +211,7 @@ public class SourceRemapper {
|
||||||
try {
|
try {
|
||||||
Files.copy(path, targetPath);
|
Files.copy(path, targetPath);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
project.getLogger().warn("Could not copy non-java sources '" + source.getName() + "' fully!", e);
|
logger.warn("Could not copy non-java sources '" + source + "' fully!", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.gradle.api.Project;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||||
|
import net.fabricmc.mappingio.MappingReader;
|
||||||
import net.fabricmc.mappingio.tree.MappingTree;
|
import net.fabricmc.mappingio.tree.MappingTree;
|
||||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||||
import net.fabricmc.tinyremapper.IMappingProvider;
|
import net.fabricmc.tinyremapper.IMappingProvider;
|
||||||
|
@ -101,6 +102,12 @@ public final class TinyRemapperHelper {
|
||||||
return new IMappingProvider.Member(className, memberName, descriptor);
|
return new IMappingProvider.Member(className, memberName, descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IMappingProvider create(Path mappings, String from, String to, boolean remapLocalVariables) throws IOException {
|
||||||
|
MemoryMappingTree mappingTree = new MemoryMappingTree();
|
||||||
|
MappingReader.read(mappings, mappingTree);
|
||||||
|
return create(mappingTree, from, to, remapLocalVariables);
|
||||||
|
}
|
||||||
|
|
||||||
public static IMappingProvider create(MappingTree mappings, String from, String to, boolean remapLocalVariables) {
|
public static IMappingProvider create(MappingTree mappings, String from, String to, boolean remapLocalVariables) {
|
||||||
return (acceptor) -> {
|
return (acceptor) -> {
|
||||||
for (MappingTree.ClassMapping classDef : mappings.getClasses()) {
|
for (MappingTree.ClassMapping classDef : mappings.getClasses()) {
|
||||||
|
|
|
@ -28,7 +28,7 @@ import org.gradle.util.GradleVersion
|
||||||
|
|
||||||
class LoomTestConstants {
|
class LoomTestConstants {
|
||||||
public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion()
|
public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion()
|
||||||
public final static String PRE_RELEASE_GRADLE = "7.4-20211216231505+0000"
|
public final static String PRE_RELEASE_GRADLE = "7.4-20211219231013+0000"
|
||||||
|
|
||||||
public final static String[] STANDARD_TEST_VERSIONS = [DEFAULT_GRADLE, PRE_RELEASE_GRADLE]
|
public final static String[] STANDARD_TEST_VERSIONS = [DEFAULT_GRADLE, PRE_RELEASE_GRADLE]
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait {
|
||||||
setup:
|
setup:
|
||||||
def gradle = gradleProject(
|
def gradle = gradleProject(
|
||||||
repo: "https://github.com/FabricMC/fabric.git",
|
repo: "https://github.com/FabricMC/fabric.git",
|
||||||
commit: "ce6198f63bbe0e17ba631420e9186fb72cc8b2af",
|
commit: "71b634e5b7845296b11be3fa6545f4fbfacc017f",
|
||||||
version: version,
|
version: version,
|
||||||
patch: "fabric_api"
|
patch: "fabric_api"
|
||||||
)
|
)
|
||||||
|
|
|
@ -47,7 +47,7 @@ class MixinApSimpleTest extends Specification implements GradleProjectTestTrait
|
||||||
result.task(":build").outcome == SUCCESS
|
result.task(":build").outcome == SUCCESS
|
||||||
|
|
||||||
// verify the ref-map name is correctly generated
|
// verify the ref-map name is correctly generated
|
||||||
def main = new JarFile(gradle.getOutputFile("fabric-example-mod-1.0.0-dev.jar").absoluteFile)
|
def main = new JarFile(new File(gradle.projectDir, "build/devlibs/fabric-example-mod-1.0.0-dev.jar").absoluteFile)
|
||||||
main.getEntry("main-refmap0000.json") != null
|
main.getEntry("main-refmap0000.json") != null
|
||||||
def mixin = new JarFile(gradle.getOutputFile("fabric-example-mod-1.0.0-mixin.jar").absoluteFile)
|
def mixin = new JarFile(gradle.getOutputFile("fabric-example-mod-1.0.0-mixin.jar").absoluteFile)
|
||||||
mixin.getEntry("default-refmap0000.json") != null
|
mixin.getEntry("default-refmap0000.json") != null
|
||||||
|
|
|
@ -45,9 +45,6 @@ class MultiProjectTest extends Specification implements GradleProjectTestTrait {
|
||||||
result.task(":core:build").outcome == SUCCESS
|
result.task(":core:build").outcome == SUCCESS
|
||||||
result.task(":example:build").outcome == SUCCESS
|
result.task(":example:build").outcome == SUCCESS
|
||||||
|
|
||||||
result.task(":remapAllJars").outcome == SUCCESS
|
|
||||||
result.task(":remapAllSources").outcome == SUCCESS
|
|
||||||
|
|
||||||
gradle.hasOutputZipEntry("multiproject-1.0.0.jar", "META-INF/jars/example-1.0.0.jar")
|
gradle.hasOutputZipEntry("multiproject-1.0.0.jar", "META-INF/jars/example-1.0.0.jar")
|
||||||
gradle.hasOutputZipEntry("multiproject-1.0.0.jar", "META-INF/jars/core-1.0.0.jar")
|
gradle.hasOutputZipEntry("multiproject-1.0.0.jar", "META-INF/jars/core-1.0.0.jar")
|
||||||
gradle.hasOutputZipEntry("multiproject-1.0.0.jar", "META-INF/jars/fabric-api-base-0.2.1+9354966b7d.jar")
|
gradle.hasOutputZipEntry("multiproject-1.0.0.jar", "META-INF/jars/fabric-api-base-0.2.1+9354966b7d.jar")
|
||||||
|
|
|
@ -51,6 +51,7 @@ class SimpleProjectTest extends Specification implements GradleProjectTestTrait
|
||||||
then:
|
then:
|
||||||
result.task(":build").outcome == SUCCESS
|
result.task(":build").outcome == SUCCESS
|
||||||
gradle.getOutputZipEntry("fabric-example-mod-1.0.0.jar", "META-INF/MANIFEST.MF").contains("Fabric-Loom-Version: 0.0.0+unknown")
|
gradle.getOutputZipEntry("fabric-example-mod-1.0.0.jar", "META-INF/MANIFEST.MF").contains("Fabric-Loom-Version: 0.0.0+unknown")
|
||||||
|
gradle.getOutputZipEntry("fabric-example-mod-1.0.0-sources.jar", "net/fabricmc/example/mixin/ExampleMixin.java").contains("class_442") // Very basic test to ensure sources got remapped
|
||||||
|
|
||||||
serverResult.successful()
|
serverResult.successful()
|
||||||
serverResult.output.contains("Hello simple Fabric mod") // A check to ensure our mod init was actually called
|
serverResult.output.contains("Hello simple Fabric mod") // A check to ensure our mod init was actually called
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
|
||||||
*
|
|
||||||
* Copyright (c) 2016-2021 FabricMC
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.fabricmc.loom.test.unit
|
|
||||||
|
|
||||||
import net.fabricmc.loom.build.nesting.MergedNestedJarProvider
|
|
||||||
import net.fabricmc.loom.build.nesting.NestedJarProvider
|
|
||||||
import org.gradle.api.Project
|
|
||||||
import spock.lang.Specification
|
|
||||||
|
|
||||||
class MergedNestedJarProviderTest extends Specification {
|
|
||||||
def "empty test"() {
|
|
||||||
given:
|
|
||||||
def nestedJarProvider = new MergedNestedJarProvider(new TestNestedJarProvider())
|
|
||||||
when:
|
|
||||||
nestedJarProvider.prepare(null)
|
|
||||||
then:
|
|
||||||
nestedJarProvider.provide() != null
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestNestedJarProvider implements NestedJarProvider {
|
|
||||||
private Collection<File> files = null
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Collection<File> provide() {
|
|
||||||
return files
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void prepare(Project project) {
|
|
||||||
files = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
diff --git a/build.gradle b/build.gradle
|
diff --git a/build.gradle b/build.gradle
|
||||||
--- a/build.gradle (revision ce6198f63bbe0e17ba631420e9186fb72cc8b2af)
|
--- a/build.gradle (revision 71b634e5b7845296b11be3fa6545f4fbfacc017f)
|
||||||
+++ b/build.gradle (date 1637848132986)
|
+++ b/build.gradle (date 1638654919842)
|
||||||
@@ -31,17 +31,7 @@
|
@@ -31,17 +31,7 @@
|
||||||
throw new NullPointerException("Could not find version for " + project.name)
|
throw new NullPointerException("Could not find version for " + project.name)
|
||||||
}
|
}
|
||||||
|
@ -20,43 +20,3 @@ diff --git a/build.gradle b/build.gradle
|
||||||
}
|
}
|
||||||
|
|
||||||
def getBranch() {
|
def getBranch() {
|
||||||
@@ -132,9 +122,8 @@
|
|
||||||
include "**/*.java"
|
|
||||||
}
|
|
||||||
|
|
||||||
- task sourcesJar(type: Jar, dependsOn: classes) {
|
|
||||||
- archiveClassifier = "sources"
|
|
||||||
- from sourceSets.main.allSource
|
|
||||||
+ java {
|
|
||||||
+ withSourcesJar()
|
|
||||||
}
|
|
||||||
|
|
||||||
checkstyle {
|
|
||||||
@@ -229,12 +218,16 @@
|
|
||||||
publications {
|
|
||||||
mavenJava(MavenPublication) {
|
|
||||||
from components.java
|
|
||||||
+
|
|
||||||
+ artifact javadocJar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setupRepositories(repositories)
|
|
||||||
}
|
|
||||||
|
|
||||||
+ loom.disableDeprecatedPomGeneration(publishing.publications.mavenJava)
|
|
||||||
+
|
|
||||||
javadoc.enabled = false
|
|
||||||
|
|
||||||
afterEvaluate {
|
|
||||||
@@ -242,10 +235,6 @@
|
|
||||||
genSourcesWithFernFlower.enabled = false
|
|
||||||
genSourcesWithCfr.enabled = false
|
|
||||||
unpickJar.enabled = false
|
|
||||||
-
|
|
||||||
- // Work around a loom bug causing empty jars to be pushed to maven local.
|
|
||||||
- publishMavenJavaPublicationToMavenLocal.dependsOn rootProject.tasks.getByName("remapAllJars")
|
|
||||||
- publishMavenJavaPublicationToMavenLocal.dependsOn rootProject.tasks.getByName("remapAllSources")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,9 @@ dependencies {
|
||||||
|
|
||||||
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
|
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
|
||||||
// You may need to force-disable transitiveness on them.
|
// You may need to force-disable transitiveness on them.
|
||||||
|
|
||||||
|
// Example include
|
||||||
|
include "org.xerial:sqlite-jdbc:3.36.0.3"
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
|
Loading…
Reference in a new issue