Mod Remapping Refactor. (#362)
Improved gradle 7 support General cleanup
This commit is contained in:
		
							parent
							
								
									e9c7c21ede
								
							
						
					
					
						commit
						7231b9e053
					
				
					 13 changed files with 689 additions and 356 deletions
				
			
		
							
								
								
									
										95
									
								
								src/main/java/net/fabricmc/loom/build/nesting/JarNester.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/main/java/net/fabricmc/loom/build/nesting/JarNester.java
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,95 @@ | |||
| /* | ||||
|  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||
|  * | ||||
|  * Copyright (c) 2016, 2017, 2018 FabricMC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in all | ||||
|  * copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| package net.fabricmc.loom.build.nesting; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.util.Collection; | ||||
| import java.util.zip.ZipEntry; | ||||
| 
 | ||||
| import com.google.common.base.Preconditions; | ||||
| import com.google.gson.JsonArray; | ||||
| import com.google.gson.JsonElement; | ||||
| import com.google.gson.JsonObject; | ||||
| import org.gradle.api.logging.Logger; | ||||
| import org.zeroturnaround.zip.FileSource; | ||||
| import org.zeroturnaround.zip.ZipEntrySource; | ||||
| import org.zeroturnaround.zip.ZipUtil; | ||||
| import org.zeroturnaround.zip.transform.StringZipEntryTransformer; | ||||
| import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry; | ||||
| 
 | ||||
| import net.fabricmc.loom.LoomGradlePlugin; | ||||
| import net.fabricmc.loom.util.ModUtils; | ||||
| 
 | ||||
| public class JarNester { | ||||
| 	public static void nestJars(Collection<File> jars, File modJar, Logger logger) { | ||||
| 		if (jars.isEmpty()) { | ||||
| 			logger.debug("Nothing to nest into " + modJar.getName()); | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		Preconditions.checkArgument(ModUtils.isMod(modJar), "Cannot nest jars into none mod jar " + modJar.getName()); | ||||
| 
 | ||||
| 		ZipUtil.addEntries(modJar, jars.stream().map(file -> new FileSource("META-INF/jars/" + file.getName(), file)).toArray(ZipEntrySource[]::new)); | ||||
| 
 | ||||
| 		boolean didNest = ZipUtil.transformEntries(modJar, single(new ZipEntryTransformerEntry("fabric.mod.json", new StringZipEntryTransformer() { | ||||
| 			@Override | ||||
| 			protected String transform(ZipEntry zipEntry, String input) { | ||||
| 				JsonObject json = LoomGradlePlugin.GSON.fromJson(input, JsonObject.class); | ||||
| 				JsonArray nestedJars = json.getAsJsonArray("jars"); | ||||
| 
 | ||||
| 				if (nestedJars == null || !json.has("jars")) { | ||||
| 					nestedJars = new JsonArray(); | ||||
| 				} | ||||
| 
 | ||||
| 				for (File file : jars) { | ||||
| 					String nestedJarPath = "META-INF/jars/" + file.getName(); | ||||
| 
 | ||||
| 					for (JsonElement nestedJar : nestedJars) { | ||||
| 						JsonObject jsonObject = nestedJar.getAsJsonObject(); | ||||
| 
 | ||||
| 						if (jsonObject.has("file") && jsonObject.get("file").getAsString().equals(nestedJarPath)) { | ||||
| 							throw new IllegalStateException("Cannot nest 2 jars at the same path: " + nestedJarPath); | ||||
| 						} | ||||
| 					} | ||||
| 
 | ||||
| 					JsonObject jsonObject = new JsonObject(); | ||||
| 					jsonObject.addProperty("file", nestedJarPath); | ||||
| 					nestedJars.add(jsonObject); | ||||
| 
 | ||||
| 					logger.debug("Nested " + nestedJarPath + " into " + modJar.getName()); | ||||
| 				} | ||||
| 
 | ||||
| 				json.add("jars", nestedJars); | ||||
| 
 | ||||
| 				return LoomGradlePlugin.GSON.toJson(json); | ||||
| 			} | ||||
| 		}))); | ||||
| 		Preconditions.checkArgument(didNest, "Failed to nest jars into " + modJar.getName()); | ||||
| 	} | ||||
| 
 | ||||
| 	private static ZipEntryTransformerEntry[] single(ZipEntryTransformerEntry element) { | ||||
| 		return new ZipEntryTransformerEntry[]{element}; | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,46 @@ | |||
| /* | ||||
|  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||
|  * | ||||
|  * Copyright (c) 2016, 2017, 2018 FabricMC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in all | ||||
|  * copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| package net.fabricmc.loom.build.nesting; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.util.Arrays; | ||||
| import java.util.Collection; | ||||
| import java.util.stream.Collectors; | ||||
| 
 | ||||
| public class MergedNestedJarProvider implements NestedJarProvider { | ||||
| 	private final NestedJarProvider[] parents; | ||||
| 
 | ||||
| 	public MergedNestedJarProvider(NestedJarProvider... parents) { | ||||
| 		this.parents = parents; | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public Collection<File> provide() { | ||||
| 		return Arrays.stream(parents) | ||||
| 				.map(NestedJarProvider::provide) | ||||
| 				.flatMap(Collection::stream) | ||||
| 				.collect(Collectors.toList()); | ||||
| 	} | ||||
| } | ||||
|  | @ -22,22 +22,18 @@ | |||
|  * SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| package net.fabricmc.loom.build; | ||||
| package net.fabricmc.loom.build.nesting; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.nio.file.Path; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.HashSet; | ||||
| import java.util.List; | ||||
| import java.util.Locale; | ||||
| import java.util.Set; | ||||
| import java.util.stream.Collectors; | ||||
| import java.util.zip.ZipEntry; | ||||
| 
 | ||||
| import com.google.gson.JsonArray; | ||||
| import com.google.gson.JsonObject; | ||||
| import org.apache.commons.io.FileUtils; | ||||
| import org.gradle.api.Project; | ||||
|  | @ -50,121 +46,30 @@ import org.gradle.api.artifacts.ResolvedArtifact; | |||
| import org.gradle.api.artifacts.ResolvedConfiguration; | ||||
| import org.gradle.api.artifacts.ResolvedDependency; | ||||
| import org.gradle.api.tasks.bundling.AbstractArchiveTask; | ||||
| import org.zeroturnaround.zip.FileSource; | ||||
| import org.zeroturnaround.zip.ZipEntrySource; | ||||
| import org.zeroturnaround.zip.ZipUtil; | ||||
| import org.zeroturnaround.zip.transform.StringZipEntryTransformer; | ||||
| import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry; | ||||
| 
 | ||||
| import net.fabricmc.loom.LoomGradleExtension; | ||||
| import net.fabricmc.loom.LoomGradlePlugin; | ||||
| import net.fabricmc.loom.task.RemapJarTask; | ||||
| import net.fabricmc.loom.util.Constants; | ||||
| 
 | ||||
| public class NestedJars { | ||||
| 	public static boolean addNestedJars(Project project, Path modJarPath) { | ||||
| 		List<File> containedJars = getContainedJars(project); | ||||
| public final class NestedDependencyProvider implements NestedJarProvider { | ||||
| 	final Project project; | ||||
| 	final List<DependencyInfo<?>> files; | ||||
| 
 | ||||
| 		if (containedJars.isEmpty()) { | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		File modJar = modJarPath.toFile(); | ||||
| 
 | ||||
| 		ZipUtil.addOrReplaceEntries(modJar, containedJars.stream().map(file -> new FileSource("META-INF/jars/" + file.getName(), file)).toArray(ZipEntrySource[]::new)); | ||||
| 
 | ||||
| 		return ZipUtil.transformEntries(modJar, single(new ZipEntryTransformerEntry("fabric.mod.json", new StringZipEntryTransformer() { | ||||
| 			@Override | ||||
| 			protected String transform(ZipEntry zipEntry, String input) { | ||||
| 				JsonObject json = LoomGradlePlugin.GSON.fromJson(input, JsonObject.class); | ||||
| 				JsonArray nestedJars = json.getAsJsonArray("jars"); | ||||
| 
 | ||||
| 				if (nestedJars == null || !json.has("jars")) { | ||||
| 					nestedJars = new JsonArray(); | ||||
| 				} | ||||
| 
 | ||||
| 				for (File file : containedJars) { | ||||
| 					JsonObject jsonObject = new JsonObject(); | ||||
| 					jsonObject.addProperty("file", "META-INF/jars/" + file.getName()); | ||||
| 					nestedJars.add(jsonObject); | ||||
| 				} | ||||
| 
 | ||||
| 				json.add("jars", nestedJars); | ||||
| 
 | ||||
| 				return LoomGradlePlugin.GSON.toJson(json); | ||||
| 			} | ||||
| 		}))); | ||||
| 	private NestedDependencyProvider(Project project, List<DependencyInfo<?>> files) { | ||||
| 		this.project = project; | ||||
| 		this.files = files; | ||||
| 	} | ||||
| 
 | ||||
| 	private static List<File> getContainedJars(Project project) { | ||||
| 		List<File> fileList = new ArrayList<>(); | ||||
| 	public static NestedDependencyProvider createNestedDependencyProviderFromConfiguration(Project project, Configuration configuration) { | ||||
| 		List<DependencyInfo<?>> fileList = new ArrayList<>(); | ||||
| 		Set<String> visited = new HashSet<>(); | ||||
| 
 | ||||
| 		Configuration configuration = project.getConfigurations().getByName(Constants.Configurations.INCLUDE); | ||||
| 		ResolvedConfiguration resolvedConfiguration = configuration.getResolvedConfiguration(); | ||||
| 		Set<ResolvedDependency> dependencies = resolvedConfiguration.getFirstLevelModuleDependencies(); | ||||
| 		fileList.addAll(populateProjectDependencies(configuration, visited)); | ||||
| 		fileList.addAll(populateResolvedDependencies(configuration, visited)); | ||||
| 
 | ||||
| 		// Bit ugly doing this, id guess there is a better way but this works. | ||||
| 		Set<String> projectDeps = new HashSet<>(); | ||||
| 
 | ||||
| 		for (Dependency dependency : configuration.getDependencies()) { | ||||
| 			if (dependency instanceof ProjectDependency) { | ||||
| 				ProjectDependency projectDependency = (ProjectDependency) dependency; | ||||
| 				Project dependencyProject = projectDependency.getDependencyProject(); | ||||
| 
 | ||||
| 				projectDeps.add(dependency.getGroup() + ":" + dependency.getName() + ":" + dependency.getVersion()); | ||||
| 
 | ||||
| 				// TODO change this to allow just normal jar tasks, so a project can have a none loom sub project | ||||
| 				Collection<Task> remapJarTasks = dependencyProject.getTasksByName("remapJar", false); | ||||
| 				Collection<Task> jarTasks = dependencyProject.getTasksByName("jar", false); | ||||
| 
 | ||||
| 				for (Task task : remapJarTasks.isEmpty() ? jarTasks : remapJarTasks) { | ||||
| 					if (task instanceof RemapJarTask) { | ||||
| 						fileList.addAll(prepareForNesting( | ||||
| 								Collections.singleton(((RemapJarTask) task).getArchivePath()), | ||||
| 								projectDependency, | ||||
| 								new ProjectDependencyMetaExtractor(), | ||||
| 								project | ||||
| 						)); | ||||
| 					} else if (task instanceof AbstractArchiveTask) { | ||||
| 						fileList.addAll(prepareForNesting( | ||||
| 								Collections.singleton(((AbstractArchiveTask) task).getArchivePath()), | ||||
| 								projectDependency, | ||||
| 								new ProjectDependencyMetaExtractor(), | ||||
| 								project | ||||
| 						)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		for (ResolvedDependency dependency : dependencies) { | ||||
| 			if (projectDeps.contains(dependency.getModuleGroup() + ":" + dependency.getModuleName() + ":" + dependency.getModuleVersion())) { | ||||
| 				continue; | ||||
| 			} else { | ||||
| 				fileList.addAll(prepareForNesting( | ||||
| 						dependency | ||||
| 								.getModuleArtifacts() | ||||
| 								.stream() | ||||
| 								.map(ResolvedArtifact::getFile) | ||||
| 								.collect(Collectors.toSet()), | ||||
| 						dependency, | ||||
| 						new ResolvedDependencyMetaExtractor(), | ||||
| 						project | ||||
| 				)); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		for (File file : fileList) { | ||||
| 			if (!file.exists()) { | ||||
| 				throw new RuntimeException("Failed to include nested jars, as it could not be found @ " + file.getAbsolutePath()); | ||||
| 			} | ||||
| 
 | ||||
| 			if (file.isDirectory() || !file.getName().endsWith(".jar")) { | ||||
| 				throw new RuntimeException("Failed to include nested jars, as file was not a jar: " + file.getAbsolutePath()); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return fileList; | ||||
| 		return new NestedDependencyProvider(project, fileList); | ||||
| 	} | ||||
| 
 | ||||
| 	// Looks for any deps that require a sub project to be built first | ||||
|  | @ -190,11 +95,69 @@ public class NestedJars { | |||
| 		return remapTasks; | ||||
| 	} | ||||
| 
 | ||||
| 	//This is a good place to do pre-nesting operations, such as adding a fabric.mod.json to a library | ||||
| 	private static <D> List<File> prepareForNesting(Set<File> files, D dependency, DependencyMetaExtractor<D> metaExtractor, Project project) { | ||||
| 	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 projectDependency = (ProjectDependency) dependency; | ||||
| 				Project dependencyProject = projectDependency.getDependencyProject(); | ||||
| 
 | ||||
| 				visited.add(dependency.getGroup() + ":" + dependency.getName() + ":" + dependency.getVersion()); | ||||
| 
 | ||||
| 				// TODO change this to allow just normal jar tasks, so a project can have a none loom sub project | ||||
| 				Collection<Task> remapJarTasks = dependencyProject.getTasksByName("remapJar", false); | ||||
| 				Collection<Task> jarTasks = dependencyProject.getTasksByName("jar", false); | ||||
| 
 | ||||
| 				for (Task task : remapJarTasks.isEmpty() ? jarTasks : remapJarTasks) { | ||||
| 					if (task instanceof RemapJarTask) { | ||||
| 						File file = ((RemapJarTask) task).getArchivePath(); | ||||
| 						fileList.add(new DependencyInfo<>(projectDependency, new ProjectDependencyMetaExtractor(), file)); | ||||
| 					} else if (task instanceof AbstractArchiveTask) { | ||||
| 						File file = ((AbstractArchiveTask) task).getArchivePath(); | ||||
| 						fileList.add(new DependencyInfo<>(projectDependency, new ProjectDependencyMetaExtractor(), file)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return fileList; | ||||
| 	} | ||||
| 
 | ||||
| 	private static List<DependencyInfo<ResolvedDependency>> populateResolvedDependencies(Configuration configuration, Set<String> visited) { | ||||
| 		ResolvedConfiguration resolvedConfiguration = configuration.getResolvedConfiguration(); | ||||
| 		Set<ResolvedDependency> dependencies = resolvedConfiguration.getFirstLevelModuleDependencies(); | ||||
| 
 | ||||
| 		List<DependencyInfo<ResolvedDependency>> fileList = new ArrayList<>(); | ||||
| 
 | ||||
| 		for (ResolvedDependency dependency : dependencies) { | ||||
| 			if (visited.contains(dependency.getModuleGroup() + ":" + dependency.getModuleName() + ":" + dependency.getModuleVersion())) { | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			List<File> files = dependency | ||||
| 					.getModuleArtifacts() | ||||
| 					.stream() | ||||
| 					.map(ResolvedArtifact::getFile) | ||||
| 					.collect(Collectors.toList()); | ||||
| 
 | ||||
| 			for (File file : files) { | ||||
| 				fileList.add(new DependencyInfo<>(dependency, new ResolvedDependencyMetaExtractor(), file)); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return fileList; | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public List<File> provide() { | ||||
| 		List<File> fileList = new ArrayList<>(); | ||||
| 
 | ||||
| 		for (File file : files) { | ||||
| 		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 (!ZipUtil.containsEntry(file, "fabric.mod.json")) { | ||||
| 				LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | ||||
|  | @ -216,7 +179,7 @@ public class NestedJars { | |||
| 					throw new RuntimeException("Failed to copy file", e); | ||||
| 				} | ||||
| 
 | ||||
| 				ZipUtil.addEntry(tempFile, "fabric.mod.json", getMod(dependency, metaExtractor).getBytes()); | ||||
| 				ZipUtil.addEntry(tempFile, "fabric.mod.json", generateModForDependency(metaFile).getBytes()); | ||||
| 				fileList.add(tempFile); | ||||
| 			} else { | ||||
| 				// Default copy the jar right in | ||||
|  | @ -228,7 +191,10 @@ public class NestedJars { | |||
| 	} | ||||
| 
 | ||||
| 	// Generates a barebones mod for a dependency | ||||
| 	private static <D> String getMod(D dependency, DependencyMetaExtractor<D> metaExtractor) { | ||||
| 	private static <D> String generateModForDependency(DependencyInfo<D> info) { | ||||
| 		DependencyMetaExtractor<D> metaExtractor = info.metaExtractor; | ||||
| 		D dependency = info.dependency; | ||||
| 
 | ||||
| 		JsonObject jsonObject = new JsonObject(); | ||||
| 		jsonObject.addProperty("schemaVersion", 1); | ||||
| 		jsonObject.addProperty("id", (metaExtractor.group(dependency) + "_" + metaExtractor.name(dependency)).replaceAll("\\.", "_").toLowerCase(Locale.ENGLISH)); | ||||
|  | @ -242,8 +208,26 @@ public class NestedJars { | |||
| 		return LoomGradlePlugin.GSON.toJson(jsonObject); | ||||
| 	} | ||||
| 
 | ||||
| 	private static ZipEntryTransformerEntry[] single(ZipEntryTransformerEntry element) { | ||||
| 		return new ZipEntryTransformerEntry[]{element}; | ||||
| 	private static class DependencyInfo<D> { | ||||
| 		final D dependency; | ||||
| 		final DependencyMetaExtractor<D> metaExtractor; | ||||
| 		final File file; | ||||
| 
 | ||||
| 		DependencyInfo(D dependency, DependencyMetaExtractor<D> metaExtractor, File file) { | ||||
| 			this.dependency = dependency; | ||||
| 			this.metaExtractor = metaExtractor; | ||||
| 			this.file = file; | ||||
| 		} | ||||
| 
 | ||||
| 		public void validateInputs() { | ||||
| 			if (!file.exists()) { | ||||
| 				throw new RuntimeException("Failed to include nested jars, as it could not be found @ " + file.getAbsolutePath()); | ||||
| 			} | ||||
| 
 | ||||
| 			if (file.isDirectory() || !file.getName().endsWith(".jar")) { | ||||
| 				throw new RuntimeException("Failed to include nested jars, as file was not a jar: " + file.getAbsolutePath()); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private interface DependencyMetaExtractor<D> { | ||||
|  | @ -0,0 +1,67 @@ | |||
| /* | ||||
|  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||
|  * | ||||
|  * Copyright (c) 2016, 2017, 2018 FabricMC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in all | ||||
|  * copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| package net.fabricmc.loom.build.nesting; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.util.Collection; | ||||
| import java.util.Set; | ||||
| 
 | ||||
| import com.google.common.base.Preconditions; | ||||
| import org.gradle.api.Project; | ||||
| 
 | ||||
| import net.fabricmc.loom.util.ModUtils; | ||||
| 
 | ||||
| public final class NestedJarPathProvider implements NestedJarProvider { | ||||
| 	private final Set<Object> nestedPaths; | ||||
| 	private Set<File> files = null; | ||||
| 	public NestedJarPathProvider(Set<Object> nestedPaths) { | ||||
| 		this.nestedPaths = nestedPaths; | ||||
| 	} | ||||
| 
 | ||||
| 	private Set<File> resolve(Project project) { | ||||
| 		return project.files(nestedPaths).getFiles(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void prepare(Project project) { | ||||
| 		if (files == null) { | ||||
| 			files = resolve(project); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public Collection<File> provide() { | ||||
| 		validateFiles(); | ||||
| 		return files; | ||||
| 	} | ||||
| 
 | ||||
| 	private void validateFiles() { | ||||
| 		for (File file : files) { | ||||
| 			Preconditions.checkArgument(file.getName().endsWith(".jar"), String.format("Tried to nest %s but it is not a jar", file.getAbsolutePath())); | ||||
| 			Preconditions.checkArgument(file.exists(), String.format("Tried to nest jar %s but it does not exist", file.getAbsolutePath())); | ||||
| 			Preconditions.checkArgument(ModUtils.isMod(file), String.format("Cannot use nest none mod jar %s", file.getAbsolutePath())); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,40 @@ | |||
| /* | ||||
|  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||
|  * | ||||
|  * Copyright (c) 2016, 2017, 2018 FabricMC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in all | ||||
|  * copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| package net.fabricmc.loom.build.nesting; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.util.Collection; | ||||
| 
 | ||||
| import org.gradle.api.Project; | ||||
| import org.jetbrains.annotations.ApiStatus; | ||||
| 
 | ||||
| @ApiStatus.Internal | ||||
| public interface NestedJarProvider { | ||||
| 	// provide all the files to be included, they should already be resolved but can be transformed here | ||||
| 	Collection<File> provide(); | ||||
| 
 | ||||
| 	// Setup the files ready to be provided | ||||
| 	default void prepare(Project project) { } | ||||
| } | ||||
|  | @ -24,13 +24,8 @@ | |||
| 
 | ||||
| package net.fabricmc.loom.configuration; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| import org.gradle.api.Project; | ||||
| import org.gradle.api.Task; | ||||
| import org.gradle.api.UnknownTaskException; | ||||
| import org.gradle.api.artifacts.Configuration; | ||||
| import org.gradle.api.artifacts.repositories.MavenArtifactRepository; | ||||
| import org.gradle.api.plugins.JavaPlugin; | ||||
| import org.gradle.api.plugins.JavaPluginConvention; | ||||
| import org.gradle.api.tasks.SourceSet; | ||||
|  | @ -38,8 +33,6 @@ import org.gradle.api.tasks.bundling.AbstractArchiveTask; | |||
| import org.gradle.api.tasks.javadoc.Javadoc; | ||||
| 
 | ||||
| import net.fabricmc.loom.LoomGradleExtension; | ||||
| import net.fabricmc.loom.build.JarRemapper; | ||||
| import net.fabricmc.loom.build.NestedJars; | ||||
| import net.fabricmc.loom.build.mixin.JavaApInvoker; | ||||
| import net.fabricmc.loom.build.mixin.KaptApInvoker; | ||||
| import net.fabricmc.loom.build.mixin.ScalaApInvoker; | ||||
|  | @ -47,16 +40,8 @@ import net.fabricmc.loom.configuration.ide.SetupIntelijRunConfigs; | |||
| import net.fabricmc.loom.configuration.providers.LaunchProvider; | ||||
| import net.fabricmc.loom.configuration.providers.MinecraftProvider; | ||||
| import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; | ||||
| import net.fabricmc.loom.task.AbstractLoomTask; | ||||
| import net.fabricmc.loom.task.RemapAllSourcesTask; | ||||
| import net.fabricmc.loom.task.RemapJarTask; | ||||
| import net.fabricmc.loom.task.RemapSourcesJarTask; | ||||
| import net.fabricmc.loom.util.Constants; | ||||
| import net.fabricmc.loom.util.SourceRemapper; | ||||
| 
 | ||||
| /** | ||||
|  * Add Minecraft dependencies to compile time. | ||||
|  */ | ||||
| public final class CompileConfiguration { | ||||
| 	private CompileConfiguration() { | ||||
| 	} | ||||
|  | @ -110,53 +95,18 @@ public final class CompileConfiguration { | |||
| 		extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, project); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Permit to add a Maven repository to a target project. | ||||
| 	 * | ||||
| 	 * @param target The target project | ||||
| 	 * @param name   The name of the repository | ||||
| 	 * @param url    The URL of the repository | ||||
| 	 * @return An object containing the name and the URL of the repository that can be modified later | ||||
| 	 */ | ||||
| 	public static MavenArtifactRepository addMavenRepo(Project target, final String name, final String url) { | ||||
| 		return target.getRepositories().maven(repo -> { | ||||
| 			repo.setName(name); | ||||
| 			repo.setUrl(url); | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	public static void configureCompile(Project project) { | ||||
| 		JavaPluginConvention javaModule = (JavaPluginConvention) project.getConvention().getPlugins().get("java"); | ||||
| 	public static void configureCompile(Project p) { | ||||
| 		JavaPluginConvention javaModule = (JavaPluginConvention) p.getConvention().getPlugins().get("java"); | ||||
| 
 | ||||
| 		SourceSet main = javaModule.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME); | ||||
| 
 | ||||
| 		Javadoc javadoc = (Javadoc) project.getTasks().getByName(JavaPlugin.JAVADOC_TASK_NAME); | ||||
| 		Javadoc javadoc = (Javadoc) p.getTasks().getByName(JavaPlugin.JAVADOC_TASK_NAME); | ||||
| 		javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath())); | ||||
| 
 | ||||
| 		project.afterEvaluate(project1 -> { | ||||
| 			LoomGradleExtension extension = project1.getExtensions().getByType(LoomGradleExtension.class); | ||||
| 		p.afterEvaluate(project -> { | ||||
| 			LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | ||||
| 
 | ||||
| 			project1.getRepositories().flatDir(flatDirectoryArtifactRepository -> { | ||||
| 				flatDirectoryArtifactRepository.dir(extension.getRootProjectBuildCache()); | ||||
| 				flatDirectoryArtifactRepository.setName("UserLocalCacheFiles"); | ||||
| 			}); | ||||
| 
 | ||||
| 			project1.getRepositories().maven(mavenArtifactRepository -> { | ||||
| 				mavenArtifactRepository.setUrl(extension.getRemappedModCache()); | ||||
| 				mavenArtifactRepository.setName("UserLocalRemappedMods"); | ||||
| 			}); | ||||
| 
 | ||||
| 			project1.getRepositories().maven(mavenArtifactRepository -> { | ||||
| 				mavenArtifactRepository.setName("Fabric"); | ||||
| 				mavenArtifactRepository.setUrl("https://maven.fabricmc.net/"); | ||||
| 			}); | ||||
| 
 | ||||
| 			project1.getRepositories().maven(mavenArtifactRepository -> { | ||||
| 				mavenArtifactRepository.setName("Mojang"); | ||||
| 				mavenArtifactRepository.setUrl("https://libraries.minecraft.net/"); | ||||
| 			}); | ||||
| 
 | ||||
| 			project1.getRepositories().mavenCentral(); | ||||
| 			MavenConfiguration.setup(project); | ||||
| 
 | ||||
| 			LoomDependencyManager dependencyManager = new LoomDependencyManager(); | ||||
| 			extension.setDependencyManager(dependencyManager); | ||||
|  | @ -165,100 +115,19 @@ public final class CompileConfiguration { | |||
| 			dependencyManager.addProvider(new MappingsProvider(project)); | ||||
| 			dependencyManager.addProvider(new LaunchProvider(project)); | ||||
| 
 | ||||
| 			dependencyManager.handleDependencies(project1); | ||||
| 			dependencyManager.handleDependencies(project); | ||||
| 
 | ||||
| 			project1.getTasks().getByName("idea").finalizedBy(project1.getTasks().getByName("genIdeaWorkspace")); | ||||
| 			project1.getTasks().getByName("eclipse").finalizedBy(project1.getTasks().getByName("genEclipseRuns")); | ||||
| 			project1.getTasks().getByName("cleanEclipse").finalizedBy(project1.getTasks().getByName("cleanEclipseRuns")); | ||||
| 			project.getTasks().getByName("idea").finalizedBy(project.getTasks().getByName("genIdeaWorkspace")); | ||||
| 			project.getTasks().getByName("eclipse").finalizedBy(project.getTasks().getByName("genEclipseRuns")); | ||||
| 			project.getTasks().getByName("cleanEclipse").finalizedBy(project.getTasks().getByName("cleanEclipseRuns")); | ||||
| 
 | ||||
| 			SetupIntelijRunConfigs.setup(project1); | ||||
| 			SetupIntelijRunConfigs.setup(project); | ||||
| 
 | ||||
| 			// Enables the default mod remapper | ||||
| 			if (extension.remapMod) { | ||||
| 				AbstractArchiveTask jarTask = (AbstractArchiveTask) project1.getTasks().getByName("jar"); | ||||
| 				RemapJarTask remapJarTask = (RemapJarTask) project1.getTasks().findByName("remapJar"); | ||||
| 
 | ||||
| 				assert remapJarTask != null; | ||||
| 
 | ||||
| 				if (!remapJarTask.getInput().isPresent()) { | ||||
| 					jarTask.setClassifier("dev"); | ||||
| 					remapJarTask.setClassifier(""); | ||||
| 					remapJarTask.getInput().set(jarTask.getArchivePath()); | ||||
| 				} | ||||
| 
 | ||||
| 				extension.getUnmappedModCollection().from(jarTask); | ||||
| 				remapJarTask.getAddNestedDependencies().set(true); | ||||
| 				remapJarTask.getRemapAccessWidener().set(true); | ||||
| 
 | ||||
| 				project1.getArtifacts().add("archives", remapJarTask); | ||||
| 				remapJarTask.dependsOn(jarTask); | ||||
| 				project1.getTasks().getByName("build").dependsOn(remapJarTask); | ||||
| 
 | ||||
| 				project.getTasks().withType(RemapJarTask.class).forEach(task -> { | ||||
| 					if (task.getAddNestedDependencies().getOrElse(false)) { | ||||
| 						NestedJars.getRequiredTasks(project1).forEach(task::dependsOn); | ||||
| 					} | ||||
| 				}); | ||||
| 
 | ||||
| 				SourceRemapper remapper = null; | ||||
| 				Task parentTask = project1.getTasks().getByName("build"); | ||||
| 
 | ||||
| 				if (extension.isShareCaches()) { | ||||
| 					Project rootProject = project.getRootProject(); | ||||
| 
 | ||||
| 					if (extension.isRootProject()) { | ||||
| 						SourceRemapper sourceRemapper = new SourceRemapper(rootProject, false); | ||||
| 						JarRemapper jarRemapper = new JarRemapper(); | ||||
| 
 | ||||
| 						remapJarTask.jarRemapper = jarRemapper; | ||||
| 
 | ||||
| 						rootProject.getTasks().register("remapAllSources", RemapAllSourcesTask.class, task -> { | ||||
| 							task.sourceRemapper = sourceRemapper; | ||||
| 							task.doLast(t -> sourceRemapper.remapAll()); | ||||
| 						}); | ||||
| 
 | ||||
| 						parentTask = rootProject.getTasks().getByName("remapAllSources"); | ||||
| 
 | ||||
| 						rootProject.getTasks().register("remapAllJars", AbstractLoomTask.class, task -> { | ||||
| 							task.doLast(t -> { | ||||
| 								try { | ||||
| 									jarRemapper.remap(); | ||||
| 								} catch (IOException e) { | ||||
| 									throw new RuntimeException("Failed to remap jars", e); | ||||
| 								} | ||||
| 							}); | ||||
| 						}); | ||||
| 					} else { | ||||
| 						parentTask = rootProject.getTasks().getByName("remapAllSources"); | ||||
| 						remapper = ((RemapAllSourcesTask) parentTask).sourceRemapper; | ||||
| 
 | ||||
| 						remapJarTask.jarRemapper = ((RemapJarTask) rootProject.getTasks().getByName("remapJar")).jarRemapper; | ||||
| 
 | ||||
| 						project1.getTasks().getByName("build").dependsOn(parentTask); | ||||
| 						project1.getTasks().getByName("build").dependsOn(rootProject.getTasks().getByName("remapAllJars")); | ||||
| 						rootProject.getTasks().getByName("remapAllJars").dependsOn(project1.getTasks().getByName("remapJar")); | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				try { | ||||
| 					AbstractArchiveTask sourcesTask = (AbstractArchiveTask) project1.getTasks().getByName("sourcesJar"); | ||||
| 
 | ||||
| 					RemapSourcesJarTask remapSourcesJarTask = (RemapSourcesJarTask) project1.getTasks().findByName("remapSourcesJar"); | ||||
| 					remapSourcesJarTask.setInput(sourcesTask.getArchivePath()); | ||||
| 					remapSourcesJarTask.setOutput(sourcesTask.getArchivePath()); | ||||
| 					remapSourcesJarTask.doLast(task -> project1.getArtifacts().add("archives", remapSourcesJarTask.getOutput())); | ||||
| 					remapSourcesJarTask.dependsOn(project1.getTasks().getByName("sourcesJar")); | ||||
| 
 | ||||
| 					if (extension.isShareCaches()) { | ||||
| 						remapSourcesJarTask.setSourceRemapper(remapper); | ||||
| 					} | ||||
| 
 | ||||
| 					parentTask.dependsOn(remapSourcesJarTask); | ||||
| 				} catch (UnknownTaskException ignored) { | ||||
| 					// pass | ||||
| 				} | ||||
| 				RemapConfiguration.setupDefaultRemap(project); | ||||
| 			} else { | ||||
| 				AbstractArchiveTask jarTask = (AbstractArchiveTask) project1.getTasks().getByName("jar"); | ||||
| 				AbstractArchiveTask jarTask = (AbstractArchiveTask) project.getTasks().getByName("jar"); | ||||
| 				extension.getUnmappedModCollection().from(jarTask); | ||||
| 			} | ||||
| 
 | ||||
|  | @ -281,7 +150,7 @@ public final class CompileConfiguration { | |||
| 			} | ||||
| 		}); | ||||
| 
 | ||||
| 		if (project.getPluginManager().hasPlugin("org.jetbrains.kotlin.kapt")) { | ||||
| 		if (p.getPluginManager().hasPlugin("org.jetbrains.kotlin.kapt")) { | ||||
| 			// If loom is applied after kapt, then kapt will use the AP arguments too early for loom to pass the arguments we need for mixin. | ||||
| 			throw new IllegalArgumentException("fabric-loom must be applied BEFORE kapt in the plugins { } block."); | ||||
| 		} | ||||
|  |  | |||
|  | @ -0,0 +1,57 @@ | |||
| /* | ||||
|  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||
|  * | ||||
|  * Copyright (c) 2016, 2017, 2018 FabricMC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in all | ||||
|  * copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| package net.fabricmc.loom.configuration; | ||||
| 
 | ||||
| import org.gradle.api.Project; | ||||
| 
 | ||||
| import net.fabricmc.loom.LoomGradleExtension; | ||||
| 
 | ||||
| public class MavenConfiguration { | ||||
| 	public static void setup(Project project) { | ||||
| 		LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | ||||
| 
 | ||||
| 		project.getRepositories().flatDir(repo -> { | ||||
| 			repo.setName("UserLocalCacheFiles"); | ||||
| 			repo.dir(extension.getRootProjectBuildCache()); | ||||
| 		}); | ||||
| 
 | ||||
| 		project.getRepositories().maven(repo -> { | ||||
| 			repo.setName("UserLocalRemappedMods"); | ||||
| 			repo.setUrl(extension.getRemappedModCache()); | ||||
| 		}); | ||||
| 
 | ||||
| 		project.getRepositories().maven(repo -> { | ||||
| 			repo.setName("Fabric"); | ||||
| 			repo.setUrl("https://maven.fabricmc.net/"); | ||||
| 		}); | ||||
| 
 | ||||
| 		project.getRepositories().maven(repo -> { | ||||
| 			repo.setName("Mojang"); | ||||
| 			repo.setUrl("https://libraries.minecraft.net/"); | ||||
| 		}); | ||||
| 
 | ||||
| 		project.getRepositories().mavenCentral(); | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,159 @@ | |||
| /* | ||||
|  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||
|  * | ||||
|  * Copyright (c) 2016, 2017, 2018 FabricMC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in all | ||||
|  * copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| package net.fabricmc.loom.configuration; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| import com.google.common.base.Preconditions; | ||||
| import org.gradle.api.Project; | ||||
| import org.gradle.api.Task; | ||||
| import org.gradle.api.UnknownTaskException; | ||||
| import org.gradle.api.plugins.JavaPlugin; | ||||
| import org.gradle.api.tasks.bundling.AbstractArchiveTask; | ||||
| import org.jetbrains.annotations.ApiStatus; | ||||
| 
 | ||||
| import net.fabricmc.loom.LoomGradleExtension; | ||||
| import net.fabricmc.loom.build.JarRemapper; | ||||
| import net.fabricmc.loom.build.nesting.NestedDependencyProvider; | ||||
| import net.fabricmc.loom.task.AbstractLoomTask; | ||||
| import net.fabricmc.loom.task.RemapAllSourcesTask; | ||||
| import net.fabricmc.loom.task.RemapJarTask; | ||||
| import net.fabricmc.loom.task.RemapSourcesJarTask; | ||||
| import net.fabricmc.loom.util.SourceRemapper; | ||||
| 
 | ||||
| public class RemapConfiguration { | ||||
| 	private static final String DEFAULT_JAR_TASK_NAME = JavaPlugin.JAR_TASK_NAME; | ||||
| 	private static final String DEFAULT_SOURCES_JAR_TASK_NAME = "sourcesJar"; | ||||
| 	private static final String DEFAULT_REMAP_JAR_TASK_NAME = "remapJar"; | ||||
| 	private static final String DEFAULT_REMAP_SOURCES_JAR_TASK_NAME = "remapSourcesJar"; | ||||
| 	private static final String DEFAULT_REMAP_ALL_JARS_TASK_NAME = "remapAllJars"; | ||||
| 	private static final String DEFAULT_REMAP_ALL_SOURCES_TASK_NAME = "remapAllSources"; | ||||
| 
 | ||||
| 	public static void setupDefaultRemap(Project project) { | ||||
| 		setupRemap(project, true, DEFAULT_JAR_TASK_NAME, DEFAULT_SOURCES_JAR_TASK_NAME, DEFAULT_REMAP_JAR_TASK_NAME, DEFAULT_REMAP_SOURCES_JAR_TASK_NAME, DEFAULT_REMAP_ALL_JARS_TASK_NAME, DEFAULT_REMAP_ALL_SOURCES_TASK_NAME); | ||||
| 	} | ||||
| 
 | ||||
| 	@ApiStatus.Experimental // This is only an api if you squint really hard, expect it to explode every 5 mins. If you must call in afterEvaluate on all projects | ||||
| 	public static void setupRemap(Project project, String jarTaskName, String sourcesJarTaskName, String remapJarTaskName, String remapSourcesJarTaskName, String remapAllJarsTaskName, String remapAllSourcesTaskName) { | ||||
| 		setupRemap(project, false, jarTaskName, sourcesJarTaskName, remapJarTaskName, remapSourcesJarTaskName, remapAllJarsTaskName, remapAllSourcesTaskName); | ||||
| 	} | ||||
| 
 | ||||
| 	// isDefaultRemap is set to true for the standard remap task, some defaults are left out when this is false. | ||||
| 	private static void setupRemap(Project project, boolean isDefaultRemap, String jarTaskName, String sourcesJarTaskName, String remapJarTaskName, String remapSourcesJarTaskName, String remapAllJarsTaskName, String remapAllSourcesTaskName) { | ||||
| 		LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | ||||
| 		AbstractArchiveTask jarTask = (AbstractArchiveTask) project.getTasks().getByName(jarTaskName); | ||||
| 		RemapJarTask remapJarTask = (RemapJarTask) project.getTasks().findByName(remapJarTaskName); | ||||
| 
 | ||||
| 		assert remapJarTask != null; | ||||
| 
 | ||||
| 		if (!remapJarTask.getInput().isPresent() && isDefaultRemap) { | ||||
| 			jarTask.setClassifier("dev"); | ||||
| 			remapJarTask.setClassifier(""); | ||||
| 			remapJarTask.getInput().set(jarTask.getArchivePath()); | ||||
| 		} | ||||
| 
 | ||||
| 		if (isDefaultRemap) { | ||||
| 			extension.getUnmappedModCollection().from(jarTask); | ||||
| 			remapJarTask.getAddNestedDependencies().set(true); | ||||
| 			remapJarTask.getRemapAccessWidener().set(true); | ||||
| 
 | ||||
| 			project.getArtifacts().add("archives", remapJarTask); | ||||
| 		} | ||||
| 
 | ||||
| 		remapJarTask.dependsOn(jarTask); | ||||
| 		project.getTasks().getByName("build").dependsOn(remapJarTask); | ||||
| 
 | ||||
| 		// TODO this might be wrong? | ||||
| 		project.getTasks().withType(RemapJarTask.class).forEach(task -> { | ||||
| 			if (task.getAddNestedDependencies().getOrElse(false)) { | ||||
| 				NestedDependencyProvider.getRequiredTasks(project).forEach(task::dependsOn); | ||||
| 			} | ||||
| 		}); | ||||
| 
 | ||||
| 		SourceRemapper remapper = null; | ||||
| 		// TODO what is this for? | ||||
| 		Task parentTask = project.getTasks().getByName("build"); | ||||
| 
 | ||||
| 		if (extension.isShareCaches()) { | ||||
| 			Project rootProject = project.getRootProject(); | ||||
| 
 | ||||
| 			if (extension.isRootProject()) { | ||||
| 				SourceRemapper sourceRemapper = new SourceRemapper(rootProject, false); | ||||
| 				JarRemapper jarRemapper = new JarRemapper(); | ||||
| 
 | ||||
| 				remapJarTask.jarRemapper = jarRemapper; | ||||
| 
 | ||||
| 				rootProject.getTasks().register(remapAllSourcesTaskName, RemapAllSourcesTask.class, task -> { | ||||
| 					task.sourceRemapper = sourceRemapper; | ||||
| 					task.doLast(t -> sourceRemapper.remapAll()); | ||||
| 				}); | ||||
| 
 | ||||
| 				parentTask = rootProject.getTasks().getByName(remapAllSourcesTaskName); | ||||
| 
 | ||||
| 				rootProject.getTasks().register(remapAllJarsTaskName, AbstractLoomTask.class, task -> { | ||||
| 					task.doLast(t -> { | ||||
| 						try { | ||||
| 							jarRemapper.remap(); | ||||
| 						} catch (IOException e) { | ||||
| 							throw new RuntimeException("Failed to remap jars", e); | ||||
| 						} | ||||
| 					}); | ||||
| 				}); | ||||
| 			} else { | ||||
| 				parentTask = rootProject.getTasks().getByName(remapAllSourcesTaskName); | ||||
| 				remapper = ((RemapAllSourcesTask) parentTask).sourceRemapper; | ||||
| 				Preconditions.checkNotNull(remapper); | ||||
| 
 | ||||
| 				remapJarTask.jarRemapper = ((RemapJarTask) rootProject.getTasks().getByName(remapJarTaskName)).jarRemapper; | ||||
| 
 | ||||
| 				project.getTasks().getByName("build").dependsOn(parentTask); | ||||
| 				project.getTasks().getByName("build").dependsOn(rootProject.getTasks().getByName(remapAllJarsTaskName)); | ||||
| 				rootProject.getTasks().getByName(remapAllJarsTaskName).dependsOn(project.getTasks().getByName(remapJarTaskName)); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		try { | ||||
| 			AbstractArchiveTask sourcesTask = (AbstractArchiveTask) project.getTasks().getByName(sourcesJarTaskName); | ||||
| 
 | ||||
| 			RemapSourcesJarTask remapSourcesJarTask = (RemapSourcesJarTask) project.getTasks().findByName(remapSourcesJarTaskName); | ||||
| 			Preconditions.checkNotNull(remapSourcesJarTask, "Could not find " + remapSourcesJarTaskName + " in " + project.getName()); | ||||
| 			remapSourcesJarTask.setInput(sourcesTask.getArchivePath()); | ||||
| 			remapSourcesJarTask.setOutput(sourcesTask.getArchivePath()); | ||||
| 			remapSourcesJarTask.dependsOn(project.getTasks().getByName(sourcesJarTaskName)); | ||||
| 
 | ||||
| 			if (isDefaultRemap) { | ||||
| 				remapSourcesJarTask.doLast(task -> project.getArtifacts().add("archives", remapSourcesJarTask.getOutput())); | ||||
| 			} | ||||
| 
 | ||||
| 			if (extension.isShareCaches()) { | ||||
| 				remapSourcesJarTask.setSourceRemapper(remapper); | ||||
| 			} | ||||
| 
 | ||||
| 			parentTask.dependsOn(remapSourcesJarTask); | ||||
| 		} catch (UnknownTaskException ignored) { | ||||
| 			// pass | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -30,11 +30,15 @@ import java.io.IOException; | |||
| 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.List; | ||||
| import java.util.Set; | ||||
| 
 | ||||
| import com.google.common.base.Preconditions; | ||||
| import org.gradle.api.Action; | ||||
| import org.gradle.api.Project; | ||||
| import org.gradle.api.artifacts.Configuration; | ||||
| import org.gradle.api.file.FileCollection; | ||||
| import org.gradle.api.file.RegularFileProperty; | ||||
| import org.gradle.api.provider.Property; | ||||
|  | @ -42,49 +46,64 @@ import org.gradle.api.tasks.Input; | |||
| import org.gradle.api.tasks.InputFile; | ||||
| import org.gradle.api.tasks.TaskAction; | ||||
| import org.gradle.jvm.tasks.Jar; | ||||
| import org.jetbrains.annotations.ApiStatus; | ||||
| import org.zeroturnaround.zip.ZipUtil; | ||||
| 
 | ||||
| import net.fabricmc.loom.LoomGradleExtension; | ||||
| import net.fabricmc.loom.build.JarRemapper; | ||||
| import net.fabricmc.loom.build.MixinRefmapHelper; | ||||
| import net.fabricmc.loom.build.NestedJars; | ||||
| import net.fabricmc.loom.build.nesting.NestedJarPathProvider; | ||||
| import net.fabricmc.loom.build.nesting.JarNester; | ||||
| import net.fabricmc.loom.build.nesting.MergedNestedJarProvider; | ||||
| import net.fabricmc.loom.build.nesting.NestedDependencyProvider; | ||||
| import net.fabricmc.loom.build.nesting.NestedJarProvider; | ||||
| import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor; | ||||
| import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; | ||||
| import net.fabricmc.loom.util.Constants; | ||||
| import net.fabricmc.loom.util.TinyRemapperMappingsHelper; | ||||
| import net.fabricmc.loom.util.ZipReprocessorUtil; | ||||
| import net.fabricmc.loom.util.gradle.GradleSupport; | ||||
| import net.fabricmc.stitch.util.Pair; | ||||
| import net.fabricmc.tinyremapper.OutputConsumerPath; | ||||
| import net.fabricmc.tinyremapper.TinyRemapper; | ||||
| import net.fabricmc.tinyremapper.TinyUtils; | ||||
| 
 | ||||
| public class RemapJarTask extends Jar { | ||||
| 	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<>(); | ||||
| 
 | ||||
| 	public RemapJarTask() { | ||||
| 		super(); | ||||
| 		input = GradleSupport.getfileProperty(getProject()); | ||||
| 		addNestedDependencies = getProject().getObjects().property(Boolean.class); | ||||
| 		addDefaultNestedDependencies = getProject().getObjects().property(Boolean.class); | ||||
| 		remapAccessWidener = getProject().getObjects().property(Boolean.class); | ||||
| 		// false by default, I have no idea why I have to do it for this property and not the other one | ||||
| 		remapAccessWidener.set(false); | ||||
| 		addDefaultNestedDependencies.set(true); | ||||
| 	} | ||||
| 
 | ||||
| 	@TaskAction | ||||
| 	public void doTask() throws Throwable { | ||||
| 		boolean singleRemap = false; | ||||
| 
 | ||||
| 		if (jarRemapper == null) { | ||||
| 			doSingleRemap(); | ||||
| 		} else { | ||||
| 			scheduleRemap(); | ||||
| 			singleRemap = true; | ||||
| 			jarRemapper = new JarRemapper(); | ||||
| 		} | ||||
| 
 | ||||
| 		scheduleRemap(singleRemap || getProject().getExtensions().getByType(LoomGradleExtension.class).isRootProject()); | ||||
| 
 | ||||
| 		if (singleRemap) { | ||||
| 			jarRemapper.remap(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public void doSingleRemap() throws Throwable { | ||||
| 	public void scheduleRemap(boolean isMainRemapTask) throws Throwable { | ||||
| 		Project project = getProject(); | ||||
| 		LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | ||||
| 		Path input = this.getInput().getAsFile().get().toPath(); | ||||
|  | @ -99,86 +118,7 @@ public class RemapJarTask extends Jar { | |||
| 		String fromM = "named"; | ||||
| 		String toM = "intermediary"; | ||||
| 
 | ||||
| 		Path[] classpath = getRemapClasspath(); | ||||
| 
 | ||||
| 		TinyRemapper.Builder remapperBuilder = TinyRemapper.newRemapper(); | ||||
| 
 | ||||
| 		remapperBuilder = remapperBuilder.withMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM, false)); | ||||
| 
 | ||||
| 		for (File mixinMapFile : extension.getAllMixinMappings()) { | ||||
| 			if (mixinMapFile.exists()) { | ||||
| 				remapperBuilder = remapperBuilder.withMappings(TinyUtils.createTinyMappingProvider(mixinMapFile.toPath(), fromM, toM)); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// Apply any requested options to tiny remapper | ||||
| 		for (Action<TinyRemapper.Builder> remapOption : this.remapOptions) { | ||||
| 			remapOption.execute(remapperBuilder); | ||||
| 		} | ||||
| 
 | ||||
| 		project.getLogger().info(":remapping " + input.getFileName()); | ||||
| 
 | ||||
| 		StringBuilder rc = new StringBuilder("Remap classpath: "); | ||||
| 
 | ||||
| 		for (Path p : classpath) { | ||||
| 			rc.append("\n - ").append(p.toString()); | ||||
| 		} | ||||
| 
 | ||||
| 		project.getLogger().debug(rc.toString()); | ||||
| 
 | ||||
| 		TinyRemapper remapper = remapperBuilder.build(); | ||||
| 
 | ||||
| 		try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(output).build()) { | ||||
| 			outputConsumer.addNonClassFiles(input); | ||||
| 			remapper.readClassPath(classpath); | ||||
| 			remapper.readInputs(input); | ||||
| 			remapper.apply(outputConsumer); | ||||
| 		} catch (Exception e) { | ||||
| 			remapper.finish(); | ||||
| 			throw new RuntimeException("Failed to remap " + input + " to " + output, e); | ||||
| 		} | ||||
| 
 | ||||
| 		if (getRemapAccessWidener().getOrElse(false) && extension.accessWidener != null) { | ||||
| 			extension.getJarProcessorManager().getByType(AccessWidenerJarProcessor.class).remapAccessWidener(output, remapper.getRemapper()); | ||||
| 		} | ||||
| 
 | ||||
| 		remapper.finish(); | ||||
| 
 | ||||
| 		if (!Files.exists(output)) { | ||||
| 			throw new RuntimeException("Failed to remap " + input + " to " + output + " - file missing!"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (MixinRefmapHelper.addRefmapName(extension.getRefmapName(), output)) { | ||||
| 			project.getLogger().debug("Transformed mixin reference maps in output JAR!"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (getAddNestedDependencies().getOrElse(false)) { | ||||
| 			if (NestedJars.addNestedJars(project, output)) { | ||||
| 				project.getLogger().debug("Added nested jar paths to mod json"); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (isReproducibleFileOrder() || isPreserveFileTimestamps()) { | ||||
| 			ZipReprocessorUtil.reprocessZip(output.toFile(), isReproducibleFileOrder(), isPreserveFileTimestamps()); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public void scheduleRemap() throws Throwable { | ||||
| 		Project project = getProject(); | ||||
| 		LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | ||||
| 		Path input = this.getInput().getAsFile().get().toPath(); | ||||
| 		Path output = this.getArchivePath().toPath(); | ||||
| 
 | ||||
| 		if (!Files.exists(input)) { | ||||
| 			throw new FileNotFoundException(input.toString()); | ||||
| 		} | ||||
| 
 | ||||
| 		MappingsProvider mappingsProvider = extension.getMappingsProvider(); | ||||
| 
 | ||||
| 		String fromM = "named"; | ||||
| 		String toM = "intermediary"; | ||||
| 
 | ||||
| 		if (extension.isRootProject()) { | ||||
| 		if (isMainRemapTask) { | ||||
| 			jarRemapper.addToClasspath(getRemapClasspath()); | ||||
| 
 | ||||
| 			jarRemapper.addMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM, false)); | ||||
|  | @ -193,6 +133,9 @@ public class RemapJarTask extends Jar { | |||
| 		// Add remap options to the jar remapper | ||||
| 		jarRemapper.addOptions(this.remapOptions); | ||||
| 
 | ||||
| 		NestedJarProvider nestedJarProvider = getNestedJarProvider(); | ||||
| 		nestedJarProvider.prepare(getProject()); | ||||
| 
 | ||||
| 		jarRemapper.scheduleRemap(input, output) | ||||
| 				.supplyAccessWidener((remapData, remapper) -> { | ||||
| 					if (getRemapAccessWidener().getOrElse(false) && extension.accessWidener != null) { | ||||
|  | @ -223,9 +166,7 @@ public class RemapJarTask extends Jar { | |||
| 					} | ||||
| 
 | ||||
| 					if (getAddNestedDependencies().getOrElse(false)) { | ||||
| 						if (NestedJars.addNestedJars(project, output)) { | ||||
| 							project.getLogger().debug("Added nested jar paths to mod json"); | ||||
| 						} | ||||
| 						JarNester.nestJars(nestedJarProvider.provide(), output.toFile(), project.getLogger()); | ||||
| 					} | ||||
| 
 | ||||
| 					if (accessWidener != null) { | ||||
|  | @ -235,6 +176,25 @@ public class RemapJarTask extends Jar { | |||
| 				}); | ||||
| 	} | ||||
| 
 | ||||
| 	private NestedJarProvider getNestedJarProvider() { | ||||
| 		Configuration includeConfiguration = getProject().getConfigurations().getByName(Constants.Configurations.INCLUDE); | ||||
| 
 | ||||
| 		if (!addDefaultNestedDependencies.getOrElse(true)) { | ||||
| 			return new NestedJarPathProvider(nestedPaths); | ||||
| 		} | ||||
| 
 | ||||
| 		NestedJarProvider baseProvider = NestedDependencyProvider.createNestedDependencyProviderFromConfiguration(getProject(), includeConfiguration); | ||||
| 
 | ||||
| 		if (nestedPaths.isEmpty()) { | ||||
| 			return baseProvider; | ||||
| 		} | ||||
| 
 | ||||
| 		return new MergedNestedJarProvider( | ||||
| 				baseProvider, | ||||
| 				new NestedJarPathProvider(nestedPaths) | ||||
| 		); | ||||
| 	} | ||||
| 
 | ||||
| 	private Path[] getRemapClasspath() { | ||||
| 		FileCollection files = this.classpath; | ||||
| 
 | ||||
|  | @ -258,6 +218,11 @@ public class RemapJarTask extends Jar { | |||
| 		return addNestedDependencies; | ||||
| 	} | ||||
| 
 | ||||
| 	@Input | ||||
| 	public Property<Boolean> getAddDefaultNestedDependencies() { | ||||
| 		return addDefaultNestedDependencies; | ||||
| 	} | ||||
| 
 | ||||
| 	@Input | ||||
| 	public Property<Boolean> getRemapAccessWidener() { | ||||
| 		return remapAccessWidener; | ||||
|  | @ -276,4 +241,12 @@ public class RemapJarTask extends Jar { | |||
| 
 | ||||
| 		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; | ||||
| 	} | ||||
| } | ||||
|  |  | |||
							
								
								
									
										42
									
								
								src/main/java/net/fabricmc/loom/util/ModUtils.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/main/java/net/fabricmc/loom/util/ModUtils.java
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| /* | ||||
|  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||
|  * | ||||
|  * Copyright (c) 2016, 2017, 2018 FabricMC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in all | ||||
|  * copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| package net.fabricmc.loom.util; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.util.zip.ZipFile; | ||||
| 
 | ||||
| public final class ModUtils { | ||||
| 	private ModUtils() { | ||||
| 	} | ||||
| 
 | ||||
| 	public static boolean isMod(File input) { | ||||
| 		try (ZipFile zipFile = new ZipFile(input)) { | ||||
| 			return zipFile.getEntry("fabric.mod.json") != null; | ||||
| 		} catch (IOException e) { | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -58,9 +58,4 @@ class MultiProjectTest extends Specification implements ProjectTestTrait, Archiv | |||
| 			'6.8.3' 			| _ | ||||
| 			'7.0-milestone-2'	| _ | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	String warningMode(String gradleVersion) { | ||||
| 		"none" // TODO fix this! | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -88,7 +88,7 @@ trait ProjectTestTrait { | |||
| 			return "all" | ||||
| 		} | ||||
| 
 | ||||
| 		System.getenv().TEST_WARNING_MODE ?: 'all' | ||||
| 		'fail' | ||||
| 	} | ||||
| 
 | ||||
| 	String gradleHomeDirectory(String gradleVersion) { | ||||
|  |  | |||
|  | @ -0,0 +1,6 @@ | |||
| { | ||||
|   "schemaVersion": 1, | ||||
|   "id": "modid", | ||||
|   "version": "1.0.0", | ||||
|   "name": "Example Mod" | ||||
| } | ||||
		Loading…
	
		Reference in a new issue