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.util.List; | ||||
| import java.util.Set; | ||||
| import java.util.function.Supplier; | ||||
| 
 | ||||
| import org.cadixdev.lorenz.MappingSet; | ||||
|  | @ -36,6 +35,8 @@ import org.gradle.api.NamedDomainObjectProvider; | |||
| import org.gradle.api.Project; | ||||
| import org.gradle.api.artifacts.Configuration; | ||||
| 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.configuration.InstallerData; | ||||
|  | @ -94,9 +95,9 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { | |||
| 		return getMappingsProvider().mappedProvider; | ||||
| 	} | ||||
| 
 | ||||
| 	File getNextMixinMappings(); | ||||
| 	File getMixinMappings(SourceSet sourceSet); | ||||
| 
 | ||||
| 	Set<File> getAllMixinMappings(); | ||||
| 	FileCollection getAllMixinMappings(); | ||||
| 
 | ||||
| 	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.IOException; | ||||
| import java.io.InputStreamReader; | ||||
| import java.io.UncheckedIOException; | ||||
| import java.nio.file.Path; | ||||
| import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.Objects; | ||||
| import java.util.stream.Collectors; | ||||
| import java.util.stream.Stream; | ||||
| import java.util.stream.StreamSupport; | ||||
| import java.util.zip.ZipEntry; | ||||
| import java.util.zip.ZipFile; | ||||
|  | @ -41,74 +37,35 @@ import java.util.zip.ZipFile; | |||
| import com.google.gson.JsonArray; | ||||
| import com.google.gson.JsonObject; | ||||
| import com.google.gson.JsonPrimitive; | ||||
| import org.gradle.api.Project; | ||||
| import org.jetbrains.annotations.NotNull; | ||||
| import org.jetbrains.annotations.Nullable; | ||||
| 
 | ||||
| import net.fabricmc.loom.LoomGradleExtension; | ||||
| 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 { | ||||
| 	private MixinRefmapHelper() { } | ||||
| 
 | ||||
| 	private static final String FABRIC_MOD_JSON = "fabric.mod.json"; | ||||
| 
 | ||||
| 	public static boolean addRefmapName(Project project, Path outputPath) { | ||||
| 		try { | ||||
| 			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) { | ||||
| 	@Nullable | ||||
| 	public static JsonObject readFabricModJson(File output) { | ||||
| 		try (ZipFile zip = new ZipFile(output)) { | ||||
| 			ZipEntry entry = zip.getEntry(FABRIC_MOD_JSON); | ||||
| 
 | ||||
| 			if (entry == null) { | ||||
| 				return null; | ||||
| 			} | ||||
| 
 | ||||
| 			try (InputStreamReader reader = new InputStreamReader(zip.getInputStream(entry))) { | ||||
| 				return LoomGradlePlugin.GSON.fromJson(reader, JsonObject.class); | ||||
| 			} | ||||
| 		} 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 | ||||
| 	private static Collection<String> getMixinConfigurationFiles(JsonObject fabricModJson) { | ||||
| 	public static Collection<String> getMixinConfigurationFiles(JsonObject fabricModJson) { | ||||
| 		JsonArray mixins = fabricModJson.getAsJsonArray("mixins"); | ||||
| 
 | ||||
| 		if (mixins == null) { | ||||
|  |  | |||
|  | @ -84,7 +84,7 @@ public abstract class AnnotationProcessorInvoker<T extends Task> { | |||
| 			String refmapName = Objects.requireNonNull(MixinExtension.getMixinInformationContainer(sourceSet)).refmapNameProvider().get(); | ||||
| 			Map<String, String> args = new HashMap<>() {{ | ||||
| 					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.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.JsonObject; | ||||
| 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.Pair; | ||||
|  | @ -69,6 +69,7 @@ public class JarNester { | |||
| 
 | ||||
| 				for (File file : jars) { | ||||
| 					String nestedJarPath = "META-INF/jars/" + file.getName(); | ||||
| 					Preconditions.checkArgument(ModUtils.isMod(file), "Cannot nest none mod jar: " + file.getName()); | ||||
| 
 | ||||
| 					for (JsonElement nestedJar : nestedJars) { | ||||
| 						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.compile.JavaCompile; | ||||
| import org.gradle.api.tasks.javadoc.Javadoc; | ||||
| import org.gradle.jvm.tasks.Jar; | ||||
| 
 | ||||
| import net.fabricmc.loom.LoomGradleExtension; | ||||
| import net.fabricmc.loom.build.mixin.JavaApInvoker; | ||||
|  | @ -124,6 +123,7 @@ public final class CompileConfiguration { | |||
| 
 | ||||
| 	public static void configureCompile(Project p) { | ||||
| 		final JavaPluginExtension javaPluginExtension = p.getExtensions().getByType(JavaPluginExtension.class); | ||||
| 		LoomGradleExtension extension = LoomGradleExtension.get(p); | ||||
| 
 | ||||
| 		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())); | ||||
| 
 | ||||
| 		p.afterEvaluate(project -> { | ||||
| 			LoomGradleExtension extension = LoomGradleExtension.get(project); | ||||
| 
 | ||||
| 			LoomDependencyManager dependencyManager = new LoomDependencyManager(); | ||||
| 			extension.setDependencyManager(dependencyManager); | ||||
| 
 | ||||
|  | @ -148,14 +146,6 @@ public final class CompileConfiguration { | |||
| 
 | ||||
| 			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(); | ||||
| 
 | ||||
| 			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; | ||||
| 
 | ||||
| public record AccessWidenerFile( | ||||
| 		String name, | ||||
| 		String path, | ||||
| 		String modId, | ||||
| 		byte[] content | ||||
| ) { | ||||
|  | @ -83,7 +83,7 @@ public record AccessWidenerFile( | |||
| 
 | ||||
| 	@Override | ||||
| 	public int hashCode() { | ||||
| 		int result = Objects.hash(name, modId); | ||||
| 		int result = Objects.hash(path, modId); | ||||
| 		result = 31 * result + Arrays.hashCode(content); | ||||
| 		return result; | ||||
| 	} | ||||
|  |  | |||
|  | @ -34,14 +34,10 @@ import java.util.Arrays; | |||
| 
 | ||||
| import com.google.common.hash.Hashing; | ||||
| import org.gradle.api.Project; | ||||
| import org.objectweb.asm.commons.Remapper; | ||||
| 
 | ||||
| import net.fabricmc.accesswidener.AccessWidener; | ||||
| import net.fabricmc.accesswidener.AccessWidenerReader; | ||||
| import net.fabricmc.accesswidener.AccessWidenerRemapper; | ||||
| import net.fabricmc.accesswidener.AccessWidenerWriter; | ||||
| import net.fabricmc.loom.LoomGradleExtension; | ||||
| import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; | ||||
| import net.fabricmc.loom.configuration.processors.JarProcessor; | ||||
| 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 | ||||
| 	public boolean isInvalid(File file) { | ||||
| 		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) { | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -26,13 +26,10 @@ package net.fabricmc.loom.extension; | |||
| 
 | ||||
| import java.io.File; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.HashMap; | ||||
| import java.util.HashSet; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Objects; | ||||
| import java.util.Set; | ||||
| import java.util.function.Supplier; | ||||
| 
 | ||||
| import org.cadixdev.lorenz.MappingSet; | ||||
|  | @ -42,6 +39,8 @@ import org.gradle.api.NamedDomainObjectProvider; | |||
| import org.gradle.api.Project; | ||||
| import org.gradle.api.artifacts.Configuration; | ||||
| 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.configuration.InstallerData; | ||||
|  | @ -55,7 +54,7 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen | |||
| 	private final LoomFiles loomFiles; | ||||
| 	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 Mercury[] srcMercuryCache = new Mercury[2]; | ||||
| 	private final Map<String, NamedDomainObjectProvider<Configuration>> lazyConfigurations = new HashMap<>(); | ||||
|  | @ -70,6 +69,7 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen | |||
| 		this.project = project; | ||||
| 		// Initiate with newInstance to allow gradle to decorate our extension | ||||
| 		this.mixinApExtension = project.getObjects().newInstance(MixinExtensionImpl.class, project); | ||||
| 		this.mixinMappings = project.getObjects().fileCollection(); | ||||
| 		this.loomFiles = files; | ||||
| 		this.unmappedMods = project.files(); | ||||
| 	} | ||||
|  | @ -85,15 +85,15 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen | |||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public synchronized File getNextMixinMappings() { | ||||
| 		File mixinMapping = new File(getFiles().getProjectBuildCache(), "mixin-map-" + getMappingsProvider().mappingsIdentifier() + "." + mixinMappings.size() + ".tiny"); | ||||
| 		mixinMappings.add(mixinMapping); | ||||
| 	public synchronized File getMixinMappings(SourceSet sourceSet) { | ||||
| 		File mixinMapping = new File(getFiles().getProjectBuildCache(), "mixin-map-" + getMappingsProvider().mappingsIdentifier() + "." + sourceSet.getName() + ".tiny"); | ||||
| 		mixinMappings.from(getProject().files(mixinMapping)); | ||||
| 		return mixinMapping; | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public Set<File> getAllMixinMappings() { | ||||
| 		return mixinMappings; | ||||
| 	public FileCollection getAllMixinMappings() { | ||||
| 		return mixinMappings.filter(File::exists); | ||||
| 	} | ||||
| 
 | ||||
| 	@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); | ||||
| 		}); | ||||
| 
 | ||||
| 		tasks.register("remapJar", RemapJarTask.class, t -> { | ||||
| 			t.setDescription("Remaps the built project jar to intermediary mappings."); | ||||
| 			t.setGroup(Constants.TaskGroup.FABRIC); | ||||
| 		}); | ||||
| 		RemapTaskConfiguration.setupRemap(project); | ||||
| 
 | ||||
| 		TaskProvider<ExtractNativesTask> extractNatives = tasks.register("extractNatives", ExtractNativesTask.class); | ||||
| 		tasks.register("downloadAssets", DownloadAssetsTask.class, t -> { | ||||
| 			t.dependsOn(extractNatives); | ||||
| 			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 -> { | ||||
| 			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). | ||||
|  * | ||||
|  * Copyright (c) 2016-2021 FabricMC | ||||
|  * 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 | ||||
|  | @ -27,183 +27,233 @@ package net.fabricmc.loom.task; | |||
| import java.io.ByteArrayInputStream; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.File; | ||||
| import java.io.FileNotFoundException; | ||||
| import java.io.IOException; | ||||
| import java.io.UncheckedIOException; | ||||
| import java.io.Serializable; | ||||
| import java.nio.file.Files; | ||||
| import java.nio.file.Path; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.LinkedHashSet; | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| import java.util.Objects; | ||||
| import java.util.jar.Manifest; | ||||
| import java.util.stream.Collectors; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
| 
 | ||||
| import com.google.common.base.Preconditions; | ||||
| import org.gradle.api.Action; | ||||
| import org.gradle.api.Project; | ||||
| import com.google.gson.JsonObject; | ||||
| import org.gradle.api.artifacts.Configuration; | ||||
| import org.gradle.api.file.ConfigurableFileCollection; | ||||
| import org.gradle.api.file.FileCollection; | ||||
| import org.gradle.api.file.RegularFileProperty; | ||||
| import org.gradle.api.plugins.JavaPlugin; | ||||
| import org.gradle.api.provider.ListProperty; | ||||
| import org.gradle.api.provider.Property; | ||||
| import org.gradle.api.provider.Provider; | ||||
| 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.jvm.tasks.Jar; | ||||
| import org.jetbrains.annotations.ApiStatus; | ||||
| import org.objectweb.asm.commons.Remapper; | ||||
| 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.api.mappings.layered.MappingsNamespace; | ||||
| import net.fabricmc.loom.build.JarRemapper; | ||||
| 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.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.AccessWidenerJarProcessor; | ||||
| import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; | ||||
| import net.fabricmc.loom.extension.MixinExtension; | ||||
| 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.TinyRemapperHelper; | ||||
| import net.fabricmc.loom.util.ZipReprocessorUtil; | ||||
| 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.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 final RegularFileProperty input; | ||||
| 	private final Property<Boolean> addNestedDependencies; | ||||
| 	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<>(); | ||||
| 	@InputFiles | ||||
| 	public abstract ConfigurableFileCollection getNestedJars(); | ||||
| 
 | ||||
| 	@Input | ||||
| 	public abstract Property<Boolean> getAddNestedDependencies(); | ||||
| 
 | ||||
| 	@Inject | ||||
| 	public RemapJarTask() { | ||||
| 		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()) { | ||||
| 			remapOptions.add(b -> b.extension(new MixinExtension())); | ||||
| 		} | ||||
| 		getClasspath().from(getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME)); | ||||
| 		getAddNestedDependencies().convention(true).finalizeValueOnRead(); | ||||
| 
 | ||||
| 		Configuration includeConfiguration = getProject().getConfigurations().getByName(Constants.Configurations.INCLUDE); | ||||
| 		getNestedJars().from(new IncludedJarFactory(getProject()).getNestedJars(includeConfiguration)); | ||||
| 	} | ||||
| 
 | ||||
| 	@TaskAction | ||||
| 	public void doTask() throws Throwable { | ||||
| 		boolean singleRemap = false; | ||||
| 	public void run() { | ||||
| 		final LoomGradleExtension extension = LoomGradleExtension.get(getProject()); | ||||
| 
 | ||||
| 		if (jarRemapper == null) { | ||||
| 			singleRemap = true; | ||||
| 			jarRemapper = new JarRemapper(); | ||||
| 		submitWork(RemapAction.class, params -> { | ||||
| 			if (getAddNestedDependencies().get()) { | ||||
| 				params.getNestedJars().from(getNestedJars()); | ||||
| 			} | ||||
| 
 | ||||
| 		scheduleRemap(singleRemap || LoomGradleExtension.get(getProject()).isRootProject()); | ||||
| 			params.getJarManifestService().set(JarManifestService.get(getProject())); | ||||
| 			params.getRemapClasspath().from(getClasspath()); | ||||
| 			params.getMappings().add(MappingsService.createDefault(getProject(), getSourceNamespace().get(), getTargetNamespace().get())); | ||||
| 
 | ||||
| 		if (singleRemap) { | ||||
| 			jarRemapper.remap(); | ||||
| 			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; | ||||
| 		} | ||||
| 
 | ||||
| 		final Collection<String> allMixinConfigs = MixinRefmapHelper.getMixinConfigurationFiles(fabricModJson); | ||||
| 
 | ||||
| 		for (SourceSet sourceSet : mixinExtension.getMixinSourceSets()) { | ||||
| 			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 { | ||||
| 		Project project = getProject(); | ||||
| 		LoomGradleExtension extension = LoomGradleExtension.get(getProject()); | ||||
| 		Path input = this.getInput().getAsFile().get().toPath(); | ||||
| 		Path output = this.getArchiveFile().get().getAsFile().toPath(); | ||||
| 	public interface RemapParams extends AbstractRemapParams { | ||||
| 		ConfigurableFileCollection getNestedJars(); | ||||
| 		ConfigurableFileCollection getRemapClasspath(); | ||||
| 		ConfigurableFileCollection getMixinMappings(); | ||||
| 		ListProperty<Provider<MappingsService>> getMappings(); | ||||
| 
 | ||||
| 		if (!Files.exists(input)) { | ||||
| 			throw new FileNotFoundException(input.toString()); | ||||
| 		Property<Boolean> getUseMixinExtension(); | ||||
| 
 | ||||
| 		record RefmapData(List<String> mixinConfigs, String refmapName) implements Serializable { } | ||||
| 		ListProperty<RefmapData> getMixinData(); | ||||
| 
 | ||||
| 		Property<JarManifestService> getJarManifestService(); | ||||
| 	} | ||||
| 
 | ||||
| 		MappingsProviderImpl mappingsProvider = extension.getMappingsProvider(); | ||||
| 	public abstract static class RemapAction extends AbstractRemapAction<RemapParams> { | ||||
| 		private static final Logger LOGGER = LoggerFactory.getLogger(RemapAction.class); | ||||
| 
 | ||||
| 		String fromM = MappingsNamespace.NAMED.toString(); | ||||
| 		String toM = MappingsNamespace.INTERMEDIARY.toString(); | ||||
| 
 | ||||
| 		if (isMainRemapTask) { | ||||
| 			jarRemapper.addToClasspath(getRemapClasspath()); | ||||
| 
 | ||||
| 			jarRemapper.addMappings(TinyRemapperHelper.create(mappingsProvider.getMappings(), fromM, toM, false)); | ||||
| 		} | ||||
| 
 | ||||
| 		for (File mixinMapFile : extension.getAllMixinMappings()) { | ||||
| 			if (mixinMapFile.exists()) { | ||||
| 				jarRemapper.addMappings(TinyUtils.createTinyMappingProvider(mixinMapFile.toPath(), fromM, toM)); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// Add remap options to the jar remapper | ||||
| 		jarRemapper.addOptions(this.remapOptions); | ||||
| 
 | ||||
| 		NestedJarProvider nestedJarProvider = getNestedJarProvider(); | ||||
| 		nestedJarProvider.prepare(getProject()); | ||||
| 
 | ||||
| 		jarRemapper.scheduleRemap(input, output) | ||||
| 				.supplyAccessWidener((remapData, remapper) -> { | ||||
| 					if (getRemapAccessWidener().getOrElse(false) && extension.getAccessWidenerPath().isPresent()) { | ||||
| 						AccessWidenerJarProcessor accessWidenerJarProcessor = extension.getJarProcessorManager().getByType(AccessWidenerJarProcessor.class); | ||||
| 						byte[] data; | ||||
| 		private TinyRemapper tinyRemapper; | ||||
| 
 | ||||
| 		@Override | ||||
| 		public void execute() { | ||||
| 			try { | ||||
| 							data = accessWidenerJarProcessor.getRemappedAccessWidener(remapper, toM); | ||||
| 						} catch (IOException e) { | ||||
| 							throw new RuntimeException("Failed to remap access widener", e); | ||||
| 						} | ||||
| 				LOGGER.info("Remapping {} to {}", inputFile, outputFile); | ||||
| 
 | ||||
| 						AccessWidenerFile awFile = AccessWidenerFile.fromModJar(remapData.input); | ||||
| 						Preconditions.checkNotNull(awFile, "Failed to find accessWidener in fabric.mod.json: " + remapData.input); | ||||
| 				tinyRemapper = createTinyRemapper(); | ||||
| 
 | ||||
| 						return Pair.of(awFile.name(), data); | ||||
| 					} | ||||
| 				remap(); | ||||
| 				remapAccessWidener(); | ||||
| 				addRefmaps(); | ||||
| 				addNestedJars(); | ||||
| 				modifyJarManifest(); | ||||
| 				rewriteJar(); | ||||
| 
 | ||||
| 					return null; | ||||
| 				}) | ||||
| 				.complete((data, accessWidener) -> { | ||||
| 					if (!Files.exists(output)) { | ||||
| 						throw new RuntimeException("Failed to remap " + input + " to " + output + " - file missing!"); | ||||
| 					} | ||||
| 				tinyRemapper.finish(); | ||||
| 				tinyRemapper = null; | ||||
| 
 | ||||
| 					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) { | ||||
| 				LOGGER.debug("Finished remapping {}", inputFile); | ||||
| 			} catch (Exception e) { | ||||
| 				try { | ||||
| 							ZipUtils.replace(data.output, accessWidener.getLeft(), accessWidener.getRight()); | ||||
| 						} catch (IOException e) { | ||||
| 							throw new UncheckedIOException("Failed to replace access widener in output jar", e); | ||||
| 					Files.deleteIfExists(outputFile); | ||||
| 				} catch (IOException ex) { | ||||
| 					LOGGER.error("Failed to delete output file", ex); | ||||
| 				} | ||||
| 
 | ||||
| 				throw new RuntimeException("Failed to remap", e); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 					// Add data to the manifest | ||||
| 					try { | ||||
| 						int count = ZipUtils.transform(data.output, Map.of(MANIFEST_PATH, bytes -> { | ||||
| 		private void remap() throws IOException { | ||||
| 			final InputTag inputTag = tinyRemapper.createInputTag(); | ||||
| 
 | ||||
| 			tinyRemapper.readInputsAsync(inputTag, inputFile); | ||||
| 
 | ||||
| 			try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(outputFile).build()) { | ||||
| 				outputConsumer.addNonClassFiles(inputFile); | ||||
| 				tinyRemapper.apply(outputConsumer, inputTag); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		private void remapAccessWidener() throws IOException { | ||||
| 			final AccessWidenerFile accessWidenerFile = AccessWidenerFile.fromModJar(inputFile); | ||||
| 
 | ||||
| 			if (accessWidenerFile == null) { | ||||
| 				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); | ||||
| 		} | ||||
| 
 | ||||
| 		private static byte[] remapAccessWidener(byte[] input, Remapper asmRemapper, String targetNamespace) { | ||||
| 			int version = AccessWidenerReader.readVersion(input); | ||||
| 
 | ||||
| 			AccessWidenerWriter writer = new AccessWidenerWriter(version); | ||||
| 			AccessWidenerRemapper remapper = new AccessWidenerRemapper( | ||||
| 					writer, | ||||
| 					asmRemapper, | ||||
| 					MappingsNamespace.NAMED.toString(), | ||||
| 					targetNamespace | ||||
| 			); | ||||
| 			AccessWidenerReader reader = new AccessWidenerReader(remapper); | ||||
| 			reader.read(input); | ||||
| 
 | ||||
| 			return writer.write(); | ||||
| 		} | ||||
| 
 | ||||
| 		private void addNestedJars() { | ||||
| 			FileCollection nestedJars = getParameters().getNestedJars(); | ||||
| 
 | ||||
| 			if (nestedJars.isEmpty()) { | ||||
| 				LOGGER.info("No jars to nest"); | ||||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
| 			JarNester.nestJars(nestedJars.getFiles(), outputFile.toFile(), LOGGER); | ||||
| 		} | ||||
| 
 | ||||
| 		private void modifyJarManifest() throws IOException { | ||||
| 			int count = ZipUtils.transform(outputFile, 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); | ||||
| 				getParameters().getJarManifestService().get().apply(manifest); | ||||
| 				manifest.getMainAttributes().putValue("Fabric-Mapping-Namespace", getParameters().getTargetNamespace().get()); | ||||
| 
 | ||||
| 				ByteArrayOutputStream out = new ByteArrayOutputStream(); | ||||
| 				manifest.write(out); | ||||
|  | @ -211,92 +261,47 @@ public class RemapJarTask extends Jar { | |||
| 			})); | ||||
| 
 | ||||
| 			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 void addRefmaps() throws IOException { | ||||
| 			if (getParameters().getUseMixinExtension().get()) { | ||||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
| 	private NestedJarProvider getNestedJarProvider() { | ||||
| 		Configuration includeConfiguration = getProject().getConfigurations().getByName(Constants.Configurations.INCLUDE); | ||||
| 
 | ||||
| 		if (!addDefaultNestedDependencies.getOrElse(true)) { | ||||
| 			return new NestedJarPathProvider(nestedPaths); | ||||
| 			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()); | ||||
| 					} | ||||
| 
 | ||||
| 		NestedJarProvider baseProvider = NestedDependencyProvider.createNestedDependencyProviderFromConfiguration(getProject(), includeConfiguration); | ||||
| 
 | ||||
| 		if (nestedPaths.isEmpty()) { | ||||
| 			return baseProvider; | ||||
| 					return json; | ||||
| 				}))); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return new MergedNestedJarProvider( | ||||
| 				baseProvider, | ||||
| 				new NestedJarPathProvider(nestedPaths) | ||||
| 		); | ||||
| 		private TinyRemapper createTinyRemapper() { | ||||
| 			TinyRemapper.Builder builder = TinyRemapper.newRemapper(); | ||||
| 
 | ||||
| 			for (Provider<MappingsService> provider : getParameters().getMappings().get()) { | ||||
| 				builder.withMappings(provider.get().getMappingsProvider()); | ||||
| 			} | ||||
| 
 | ||||
| 	private Path[] getRemapClasspath() { | ||||
| 		FileCollection files = this.classpath; | ||||
| 
 | ||||
| 		if (files == null) { | ||||
| 			files = getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME); | ||||
| 			for (File mixinMapping : getParameters().getMixinMappings()) { | ||||
| 				builder.withMappings(TinyUtils.createTinyMappingProvider(mixinMapping.toPath(), getParameters().getSourceNamespace().get(), getParameters().getTargetNamespace().get())); | ||||
| 			} | ||||
| 
 | ||||
| 		return files.getFiles().stream() | ||||
| 				.map(File::toPath) | ||||
| 				.filter(Files::exists) | ||||
| 				.toArray(Path[]::new); | ||||
| 			if (getParameters().getUseMixinExtension().get()) { | ||||
| 				builder.extension(new net.fabricmc.tinyremapper.extension.mixin.MixinExtension()); | ||||
| 			} | ||||
| 
 | ||||
| 	@InputFile | ||||
| 	public RegularFileProperty getInput() { | ||||
| 		return input; | ||||
| 			TinyRemapper remapper = builder.build(); | ||||
| 
 | ||||
| 			// Apply classpath | ||||
| 			for (File file : getParameters().getRemapClasspath()) { | ||||
| 				remapper.readClassPathAsync(file.toPath()); | ||||
| 			} | ||||
| 
 | ||||
| 	@Input | ||||
| 	public Property<Boolean> getAddNestedDependencies() { | ||||
| 		return addNestedDependencies; | ||||
| 			return remapper; | ||||
| 		} | ||||
| 
 | ||||
| 	@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; | ||||
| 	} | ||||
| 
 | ||||
| 	@ApiStatus.Experimental | ||||
| 	// This only allows mod jars, proceed with care when trying to pass in configurations with projects, or something that depends on a task. | ||||
| 	public RemapJarTask include(Object... paths) { | ||||
| 		Collections.addAll(nestedPaths, paths); | ||||
| 		this.addNestedDependencies.set(true); | ||||
| 
 | ||||
| 		return this; | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| /* | ||||
|  * 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 | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  | @ -24,70 +24,65 @@ | |||
| 
 | ||||
| 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.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.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| 
 | ||||
| import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; | ||||
| import net.fabricmc.loom.util.SourceRemapper; | ||||
| 
 | ||||
| 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); | ||||
| import net.fabricmc.loom.task.service.MappingsService; | ||||
| import net.fabricmc.loom.task.service.SourceRemapperService; | ||||
| 
 | ||||
| public abstract class RemapSourcesJarTask extends AbstractRemapJarTask { | ||||
| 	@Inject | ||||
| 	public RemapSourcesJarTask() { | ||||
| 		super(); | ||||
| 
 | ||||
| 		getClasspath().from(getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME)); | ||||
| 	} | ||||
| 
 | ||||
| 	@TaskAction | ||||
| 	public void remap() throws Exception { | ||||
| 		if (sourceRemapper == null) { | ||||
| 			String direction = targetNamespace.get(); | ||||
| 			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 void run() { | ||||
| 		submitWork(RemapSourcesAction.class, params -> { | ||||
| 			params.getSourcesRemapperService().set(SourceRemapperService.create(getProject(), MappingsService.createDefault(getProject(), getSourceNamespace().get(), getTargetNamespace().get()), getClasspath())); | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	@Internal | ||||
| 	public SourceRemapper getSourceRemapper() { | ||||
| 		return sourceRemapper; | ||||
| 	public interface RemapSourcesParams extends AbstractRemapParams { | ||||
| 		Property<SourceRemapperService> getSourcesRemapperService(); | ||||
| 	} | ||||
| 
 | ||||
| 	public RemapSourcesJarTask setSourceRemapper(SourceRemapper sourceRemapper) { | ||||
| 		this.sourceRemapper = sourceRemapper; | ||||
| 		return this; | ||||
| 	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(); | ||||
| 		} | ||||
| 
 | ||||
| 	@InputFile | ||||
| 	public RegularFileProperty getInput() { | ||||
| 		return input; | ||||
| 		@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); | ||||
| 				} | ||||
| 
 | ||||
| 	@OutputFile | ||||
| 	public RegularFileProperty getOutput() { | ||||
| 		return output; | ||||
| 				throw new RuntimeException("Failed to remap sources", e); | ||||
| 			} | ||||
| 
 | ||||
| 	@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.remapper.MercuryRemapper; | ||||
| import org.gradle.api.Project; | ||||
| import org.slf4j.Logger; | ||||
| 
 | ||||
| import net.fabricmc.loom.LoomGradleExtension; | ||||
| 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); | ||||
| 		} | ||||
| 
 | ||||
| 		copyNonJavaFiles(srcPath, dstPath, project, source); | ||||
| 		copyNonJavaFiles(srcPath, dstPath, project.getLogger(), source.toPath()); | ||||
| 
 | ||||
| 		if (dstFs != null) { | ||||
| 			dstFs.close(); | ||||
|  | @ -202,7 +203,7 @@ public class SourceRemapper { | |||
| 		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 -> { | ||||
| 			Path targetPath = to.resolve(from.relativize(path).toString()); | ||||
| 
 | ||||
|  | @ -210,7 +211,7 @@ public class SourceRemapper { | |||
| 				try { | ||||
| 					Files.copy(path, targetPath); | ||||
| 				} 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.api.mappings.layered.MappingsNamespace; | ||||
| import net.fabricmc.mappingio.MappingReader; | ||||
| import net.fabricmc.mappingio.tree.MappingTree; | ||||
| import net.fabricmc.mappingio.tree.MemoryMappingTree; | ||||
| import net.fabricmc.tinyremapper.IMappingProvider; | ||||
|  | @ -101,6 +102,12 @@ public final class TinyRemapperHelper { | |||
| 		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) { | ||||
| 		return (acceptor) -> { | ||||
| 			for (MappingTree.ClassMapping classDef : mappings.getClasses()) { | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ import org.gradle.util.GradleVersion | |||
| 
 | ||||
| class LoomTestConstants { | ||||
|     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] | ||||
| } | ||||
|  |  | |||
|  | @ -44,7 +44,7 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait { | |||
| 		setup: | ||||
| 			def gradle = gradleProject( | ||||
| 					repo: "https://github.com/FabricMC/fabric.git", | ||||
| 					commit: "ce6198f63bbe0e17ba631420e9186fb72cc8b2af", | ||||
| 					commit: "71b634e5b7845296b11be3fa6545f4fbfacc017f", | ||||
| 					version: version, | ||||
| 					patch: "fabric_api" | ||||
| 			) | ||||
|  |  | |||
|  | @ -47,7 +47,7 @@ class MixinApSimpleTest extends Specification implements GradleProjectTestTrait | |||
|             result.task(":build").outcome == SUCCESS | ||||
| 
 | ||||
|             // 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 | ||||
|             def mixin = new JarFile(gradle.getOutputFile("fabric-example-mod-1.0.0-mixin.jar").absoluteFile) | ||||
|             mixin.getEntry("default-refmap0000.json") != null | ||||
|  |  | |||
|  | @ -45,9 +45,6 @@ class MultiProjectTest extends Specification implements GradleProjectTestTrait { | |||
| 			result.task(":core: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/core-1.0.0.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: | ||||
| 			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-sources.jar", "net/fabricmc/example/mixin/ExampleMixin.java").contains("class_442") // Very basic test to ensure sources got remapped | ||||
| 
 | ||||
| 			serverResult.successful() | ||||
| 			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
 | ||||
| --- a/build.gradle	(revision ce6198f63bbe0e17ba631420e9186fb72cc8b2af)
 | ||||
| +++ b/build.gradle	(date 1637848132986)
 | ||||
| --- a/build.gradle	(revision 71b634e5b7845296b11be3fa6545f4fbfacc017f)
 | ||||
| +++ b/build.gradle	(date 1638654919842)
 | ||||
| @@ -31,17 +31,7 @@
 | ||||
|  		throw new NullPointerException("Could not find version for " + project.name) | ||||
|  	} | ||||
|  | @ -20,43 +20,3 @@ diff --git a/build.gradle b/build.gradle | |||
|  } | ||||
| 
 | ||||
|  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. | ||||
| 	// You may need to force-disable transitiveness on them. | ||||
| 
 | ||||
| 	// Example include | ||||
| 	include "org.xerial:sqlite-jdbc:3.36.0.3" | ||||
| } | ||||
| 
 | ||||
| tasks.withType(JavaCompile).configureEach { | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue