From cf42acf09f4583b1cf1176cc778657d33fca7815 Mon Sep 17 00:00:00 2001 From: modmuss Date: Sat, 27 Sep 2025 09:06:29 +0100 Subject: [PATCH] Remove Guava and Commons IO Dependencies (#1372) --- build.gradle | 9 --- gradle/libs.versions.toml | 4 -- .../api/decompilers/DecompilerOptions.java | 5 +- .../loom/build/nesting/JarNester.java | 8 +-- .../nesting/NestableJarGenerationTask.java | 7 +- .../configuration/FileDependencyInfo.java | 46 ++++++++++--- .../IntermediaryMappingsProvider.java | 7 +- .../mappings/IntermediateMappingsService.java | 4 +- .../mappings/TinyMappingsService.java | 4 +- .../mappings/tiny/MappingsMerger.java | 5 +- .../minecraft/MinecraftProvider.java | 10 +-- .../minecraft/MinecraftSourceSets.java | 10 +-- .../minecraft/verify/KnownVersions.java | 5 +- .../loom/task/AbstractRemapJarTask.java | 6 +- .../net/fabricmc/loom/task/LoomTasks.java | 4 +- .../task/launch/GenerateDLIConfigTask.java | 4 +- .../task/service/LorenzMappingService.java | 4 +- .../java/net/fabricmc/loom/util/CacheKey.java | 5 +- .../java/net/fabricmc/loom/util/Check.java | 42 ++++++++++++ .../loom/util/DeletingFileVisitor.java | 4 ++ .../java/net/fabricmc/loom/util/Lazy.java | 66 +++++++++++++++++++ .../loom/util/LibraryLocationLogger.java | 6 +- .../loom/util/gradle/SourceSetReference.java | 5 +- 23 files changed, 198 insertions(+), 72 deletions(-) create mode 100644 src/main/java/net/fabricmc/loom/util/Check.java create mode 100644 src/main/java/net/fabricmc/loom/util/Lazy.java diff --git a/build.gradle b/build.gradle index 7d030bac..aaf025ef 100644 --- a/build.gradle +++ b/build.gradle @@ -93,9 +93,7 @@ dependencies { implementation gradleApi() // libraries - implementation libs.commons.io implementation libs.gson - implementation libs.guava implementation libs.bundles.asm // game handling utils @@ -228,13 +226,6 @@ checkstyle { toolVersion = libs.versions.checkstyle.get() } -// Workaround https://github.com/gradle/gradle/issues/27035 -configurations.checkstyle { - resolutionStrategy.capabilitiesResolution.withCapability("com.google.collections:google-collections") { - select("com.google.guava:guava:0") - } -} - codenarc { toolVersion = libs.versions.codenarc.get() configFile = file("codenarc.groovy") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 825021d7..55a81536 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,9 +1,7 @@ [versions] kotlin = "2.0.21" asm = "9.8" -commons-io = "2.15.1" gson = "2.10.1" -guava = "33.0.0-jre" stitch = "0.6.2" tiny-remapper = "0.11.2" @@ -28,9 +26,7 @@ asm-commons = { module = "org.ow2.asm:asm-commons", version.ref = "asm" } asm-tree = { module = "org.ow2.asm:asm-tree", version.ref = "asm" } asm-util = { module = "org.ow2.asm:asm-util", version.ref = "asm" } -commons-io = { module = "commons-io:commons-io", version.ref = "commons-io" } gson = { module = "com.google.code.gson:gson", version.ref = "gson" } -guava = { module = "com.google.guava:guava", version.ref = "guava" } fabric-stitch = { module = "net.fabricmc:stitch", version.ref = "stitch" } fabric-tiny-remapper = { module = "net.fabricmc:tiny-remapper", version.ref = "tiny-remapper" } diff --git a/src/main/java/net/fabricmc/loom/api/decompilers/DecompilerOptions.java b/src/main/java/net/fabricmc/loom/api/decompilers/DecompilerOptions.java index 931ab005..360036ae 100644 --- a/src/main/java/net/fabricmc/loom/api/decompilers/DecompilerOptions.java +++ b/src/main/java/net/fabricmc/loom/api/decompilers/DecompilerOptions.java @@ -27,12 +27,13 @@ package net.fabricmc.loom.api.decompilers; import java.io.Serializable; import java.util.Map; -import com.google.common.base.Preconditions; import org.gradle.api.Named; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; +import net.fabricmc.loom.util.Check; + public abstract class DecompilerOptions implements Named { /** * Class name for to the {@link LoomDecompiler}. @@ -75,7 +76,7 @@ public abstract class DecompilerOptions implements Named { public record Dto(String className, Map options, int maxThreads) implements Serializable { } public Dto toDto() { - Preconditions.checkArgument(getDecompilerClassName().isPresent(), "No decompiler classname specified for decompiler: " + getName()); + Check.require(getDecompilerClassName().isPresent(), "No decompiler classname specified for decompiler: " + getName()); return new Dto( getDecompilerClassName().get(), getOptions().get(), diff --git a/src/main/java/net/fabricmc/loom/build/nesting/JarNester.java b/src/main/java/net/fabricmc/loom/build/nesting/JarNester.java index 18f8b7e6..31967f3a 100644 --- a/src/main/java/net/fabricmc/loom/build/nesting/JarNester.java +++ b/src/main/java/net/fabricmc/loom/build/nesting/JarNester.java @@ -32,13 +32,13 @@ import java.util.Comparator; import java.util.stream.Collectors; import java.util.stream.Stream; -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.UncheckedIOException; import org.slf4j.Logger; +import net.fabricmc.loom.util.Check; import net.fabricmc.loom.util.Pair; import net.fabricmc.loom.util.ZipUtils; import net.fabricmc.loom.util.fmj.FabricModJsonFactory; @@ -50,7 +50,7 @@ public class JarNester { return; } - Preconditions.checkArgument(FabricModJsonFactory.isModJar(modJar), "Cannot nest jars into none mod jar " + modJar.getName()); + Check.require(FabricModJsonFactory.isModJar(modJar), "Cannot nest jars into none mod jar " + modJar.getName()); // Ensure deterministic ordering of entries in fabric.mod.json Collection sortedJars = jars.stream().sorted(Comparator.comparing(File::getName)).toList(); @@ -73,7 +73,7 @@ public class JarNester { for (File file : sortedJars) { String nestedJarPath = "META-INF/jars/" + file.getName(); - Preconditions.checkArgument(FabricModJsonFactory.isModJar(file), "Cannot nest none mod jar: " + file.getName()); + Check.require(FabricModJsonFactory.isModJar(file), "Cannot nest none mod jar: " + file.getName()); for (JsonElement nestedJar : nestedJars) { JsonObject jsonObject = nestedJar.getAsJsonObject(); @@ -95,7 +95,7 @@ public class JarNester { return json; }))); - Preconditions.checkState(count > 0, "Failed to transform fabric.mod.json"); + Check.require(count > 0, "Failed to transform fabric.mod.json"); } catch (IOException e) { throw new java.io.UncheckedIOException("Failed to nest jars into " + modJar.getName(), e); } diff --git a/src/main/java/net/fabricmc/loom/build/nesting/NestableJarGenerationTask.java b/src/main/java/net/fabricmc/loom/build/nesting/NestableJarGenerationTask.java index 48da25b4..bd494b81 100644 --- a/src/main/java/net/fabricmc/loom/build/nesting/NestableJarGenerationTask.java +++ b/src/main/java/net/fabricmc/loom/build/nesting/NestableJarGenerationTask.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.io.Serializable; import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -38,7 +39,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import com.google.gson.JsonObject; -import org.apache.commons.io.FileUtils; import org.gradle.api.artifacts.ArtifactView; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.component.ComponentIdentifier; @@ -61,6 +61,7 @@ import org.slf4j.LoggerFactory; import net.fabricmc.loom.LoomGradlePlugin; import net.fabricmc.loom.task.AbstractLoomTask; import net.fabricmc.loom.util.Checksum; +import net.fabricmc.loom.util.DeletingFileVisitor; import net.fabricmc.loom.util.ZipReprocessorUtil; import net.fabricmc.loom.util.fmj.FabricModJsonFactory; @@ -88,7 +89,7 @@ public abstract class NestableJarGenerationTask extends AbstractLoomTask { try { File targetDir = getOutputDirectory().get().getAsFile(); - FileUtils.deleteDirectory(targetDir); + DeletingFileVisitor.deleteDirectory(targetDir.toPath()); targetDir.mkdirs(); } catch (IOException e) { throw new UncheckedIOException(e); @@ -215,7 +216,7 @@ public abstract class NestableJarGenerationTask extends AbstractLoomTask { private void makeNestableJar(final File input, final File output, final String modJsonFile) { try { - FileUtils.copyFile(input, output); + Files.copy(input.toPath(), output.toPath()); } catch (IOException e) { throw new UncheckedIOException("Failed to copy mod file %s".formatted(input), e); } diff --git a/src/main/java/net/fabricmc/loom/configuration/FileDependencyInfo.java b/src/main/java/net/fabricmc/loom/configuration/FileDependencyInfo.java index 603b4c63..9b11776f 100644 --- a/src/main/java/net/fabricmc/loom/configuration/FileDependencyInfo.java +++ b/src/main/java/net/fabricmc/loom/configuration/FileDependencyInfo.java @@ -35,10 +35,8 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import com.google.common.collect.Iterables; import com.google.gson.Gson; import com.google.gson.JsonObject; -import org.apache.commons.io.FilenameUtils; import org.gradle.api.InvalidUserDataException; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; @@ -64,12 +62,12 @@ public class FileDependencyInfo extends DependencyInfo { case 0 -> //Don't think Gradle would ever let you do this throw new IllegalStateException("Empty dependency?"); case 1 -> //Single file dependency - classifierToFile.put("", Iterables.getOnlyElement(files)); + classifierToFile.put("", getOnlyElement(files)); default -> { //File collection, try work out the classifiers List sortedFiles = files.stream().sorted(Comparator.comparing(File::getName, Comparator.comparingInt(String::length))).collect(Collectors.toList()); //First element in sortedFiles is the one with the shortest name, we presume all the others are different classifier types of this - File shortest = sortedFiles.remove(0); - String shortestName = FilenameUtils.removeExtension(shortest.getName()); //name.jar -> name + File shortest = sortedFiles.removeFirst(); + String shortestName = removeExtension(shortest); //name.jar -> name for (File file : sortedFiles) { if (!file.getName().startsWith(shortestName)) { @@ -84,7 +82,7 @@ public class FileDependencyInfo extends DependencyInfo { for (File file : sortedFiles) { //Now we just have to work out what classifier type the other files are, this shouldn't even return an empty string - String classifier = FilenameUtils.removeExtension(file.getName()).substring(start); + String classifier = removeExtension(file).substring(start); //The classifier could well be separated with a dash (thing name.jar and name-sources.jar), we don't want that leading dash if (classifierToFile.put(classifier.charAt(0) == '-' ? classifier.substring(1) : classifier, file) != null) { @@ -104,7 +102,7 @@ public class FileDependencyInfo extends DependencyInfo { byte[] modJson; try { - if ("jar".equals(FilenameUtils.getExtension(root.getName())) && (modJson = ZipUtils.unpackNullable(root.toPath(), "fabric.mod.json")) != null) { + if ("jar".equals(getExtension(root)) && (modJson = ZipUtils.unpackNullable(root.toPath(), "fabric.mod.json")) != null) { //It's a Fabric mod, see how much we can extract out JsonObject json = new Gson().fromJson(new String(modJson, StandardCharsets.UTF_8), JsonObject.class); @@ -121,7 +119,7 @@ public class FileDependencyInfo extends DependencyInfo { version = json.get("version").getAsString(); } else { //Not a Fabric mod, just have to make something up - name = FilenameUtils.removeExtension(root.getName()); + name = removeExtension(root); version = "1.0"; } } catch (IOException e) { @@ -150,4 +148,36 @@ public class FileDependencyInfo extends DependencyInfo { public Set resolve() { return this.resolvedFiles; } + + private static T getOnlyElement(Set set) { + if (set.size() != 1) { + throw new IllegalArgumentException("Expected exactly one element but got " + set.size()); + } + + return set.iterator().next(); + } + + private static String removeExtension(File file) { + String filename = file.getName(); + int lastDot = filename.lastIndexOf('.'); + int lastSeparator = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\')); + + if (lastDot > lastSeparator) { + return filename.substring(0, lastDot); + } + + return filename; + } + + private static String getExtension(File file) { + String filename = file.getName(); + int lastDot = filename.lastIndexOf('.'); + int lastSeparator = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\')); + + if (lastDot > lastSeparator && lastDot != filename.length() - 1) { + return filename.substring(lastDot + 1); + } + + return ""; + } } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/IntermediaryMappingsProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/IntermediaryMappingsProvider.java index f72914e4..30da8be2 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/IntermediaryMappingsProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/IntermediaryMappingsProvider.java @@ -25,13 +25,14 @@ package net.fabricmc.loom.configuration.providers.mappings; import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import javax.inject.Inject; -import com.google.common.net.UrlEscapers; import org.gradle.api.Action; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; @@ -70,7 +71,7 @@ public abstract class IntermediaryMappingsProvider extends IntermediateMappingsP // Download and extract intermediary final Path intermediaryJarPath = Files.createTempFile(getName(), ".jar"); - final String encodedMcVersion = UrlEscapers.urlFragmentEscaper().escape(getMinecraftVersion().get()); + final String encodedMcVersion = URLEncoder.encode(getMinecraftVersion().get(), StandardCharsets.UTF_8); final String urlRaw = getIntermediaryUrl().get(); if (project != null && urlRaw.equals(LoomGradleExtensionApiImpl.DEFAULT_INTERMEDIARY_URL)) { @@ -108,7 +109,7 @@ public abstract class IntermediaryMappingsProvider extends IntermediateMappingsP @Override public @NotNull String getName() { - final String encodedMcVersion = UrlEscapers.urlFragmentEscaper().escape(getMinecraftVersion().get()); + final String encodedMcVersion = URLEncoder.encode(getMinecraftVersion().get(), StandardCharsets.UTF_8); final String urlRaw = getIntermediaryUrl().get(); if (!LoomGradleExtensionApiImpl.DEFAULT_INTERMEDIARY_URL.equals(urlRaw)) { diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/IntermediateMappingsService.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/IntermediateMappingsService.java index 16299dae..bc52ffb9 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/IntermediateMappingsService.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/IntermediateMappingsService.java @@ -33,7 +33,6 @@ import java.nio.file.Path; import java.util.Collections; import java.util.function.Supplier; -import com.google.common.base.Suppliers; import org.gradle.api.Project; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.provider.Property; @@ -48,6 +47,7 @@ import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider; +import net.fabricmc.loom.util.Lazy; import net.fabricmc.loom.util.service.Service; import net.fabricmc.loom.util.service.ServiceFactory; import net.fabricmc.loom.util.service.ServiceType; @@ -68,7 +68,7 @@ public final class IntermediateMappingsService extends Service getMinecraftVersion(); } - private final Supplier memoryMappingTree = Suppliers.memoize(this::createMemoryMappingTree); + private final Supplier memoryMappingTree = Lazy.of(this::createMemoryMappingTree); public IntermediateMappingsService(Options options, ServiceFactory serviceFactory) { super(options, serviceFactory); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/TinyMappingsService.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/TinyMappingsService.java index 6135aa23..daa4eee8 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/TinyMappingsService.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/TinyMappingsService.java @@ -29,7 +29,6 @@ import java.io.UncheckedIOException; import java.nio.file.Path; import java.util.function.Supplier; -import com.google.common.base.Suppliers; import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.FileCollection; @@ -41,6 +40,7 @@ import org.gradle.api.tasks.Optional; import org.jetbrains.annotations.Nullable; import net.fabricmc.loom.util.FileSystemUtil; +import net.fabricmc.loom.util.Lazy; import net.fabricmc.loom.util.service.Service; import net.fabricmc.loom.util.service.ServiceFactory; import net.fabricmc.loom.util.service.ServiceType; @@ -80,7 +80,7 @@ public final class TinyMappingsService extends Service mappingTree = Suppliers.memoize(() -> { + private final Supplier mappingTree = Lazy.of(() -> { Path mappings = getOptions().getMappings().getSingleFile().toPath(); if (getOptions().getZipEntryPath().isPresent()) { diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/tiny/MappingsMerger.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/tiny/MappingsMerger.java index 68c4ddc2..0a3d3a96 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/tiny/MappingsMerger.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/tiny/MappingsMerger.java @@ -33,7 +33,6 @@ import java.util.Arrays; import java.util.Map; import java.util.regex.Pattern; -import com.google.common.base.Stopwatch; import org.jetbrains.annotations.VisibleForTesting; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,7 +50,7 @@ public final class MappingsMerger { private static final Logger LOGGER = LoggerFactory.getLogger(MappingsMerger.class); public static void mergeAndSaveMappings(Path from, Path out, MinecraftProvider minecraftProvider, IntermediateMappingsService intermediateMappingsService) throws IOException { - Stopwatch stopwatch = Stopwatch.createStarted(); + long start = System.currentTimeMillis(); LOGGER.info(":merging mappings"); if (minecraftProvider.isLegacySplitOfficialNamespaceVersion()) { @@ -60,7 +59,7 @@ public final class MappingsMerger { mergeAndSaveMappings(from, out, intermediateMappingsService); } - LOGGER.info(":merged mappings in " + stopwatch.stop()); + LOGGER.info(":merged mappings in {}ms", System.currentTimeMillis() - start); } @VisibleForTesting diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.java index af4d4ecd..14fa8be9 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.java @@ -31,7 +31,6 @@ import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; -import com.google.common.base.Preconditions; import org.gradle.api.JavaVersion; import org.gradle.api.Project; import org.jetbrains.annotations.Nullable; @@ -44,6 +43,7 @@ import net.fabricmc.loom.configuration.ConfigContext; import net.fabricmc.loom.configuration.providers.BundleMetadata; import net.fabricmc.loom.configuration.providers.minecraft.verify.MinecraftJarVerification; import net.fabricmc.loom.configuration.providers.minecraft.verify.SignatureVerificationFailure; +import net.fabricmc.loom.util.Check; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.download.DownloadExecutor; import net.fabricmc.loom.util.download.GradleDownloadProgressListener; @@ -189,7 +189,7 @@ public abstract class MinecraftProvider { } private void extractBundledServerJar() throws IOException { - Preconditions.checkArgument(provideServer(), "Not configured to provide server jar"); + Check.require(provideServer(), "Not configured to provide server jar"); Objects.requireNonNull(getServerBundleMetadata(), "Cannot bundled mc jar from none bundled server jar"); LOGGER.info(":Extracting server jar from bootstrap"); @@ -220,20 +220,20 @@ public abstract class MinecraftProvider { } public File getMinecraftClientJar() { - Preconditions.checkArgument(provideClient(), "Not configured to provide client jar"); + Check.require(provideClient(), "Not configured to provide client jar"); return minecraftClientJar; } // May be null on older versions @Nullable public File getMinecraftExtractedServerJar() { - Preconditions.checkArgument(provideServer(), "Not configured to provide server jar"); + Check.require(provideServer(), "Not configured to provide server jar"); return minecraftExtractedServerJar; } // This may be the server bundler jar on newer versions prob not what you want. public File getMinecraftServerJar() { - Preconditions.checkArgument(provideServer(), "Not configured to provide server jar"); + Check.require(provideServer(), "Not configured to provide server jar"); return minecraftServerJar; } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftSourceSets.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftSourceSets.java index 78489997..f5e4b5bf 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftSourceSets.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftSourceSets.java @@ -27,7 +27,6 @@ package net.fabricmc.loom.configuration.providers.minecraft; import java.util.List; import java.util.function.BiConsumer; -import com.google.common.base.Preconditions; import org.gradle.api.Project; import org.gradle.api.artifacts.ConfigurationContainer; import org.gradle.api.plugins.JavaPlugin; @@ -37,6 +36,7 @@ import org.gradle.jvm.tasks.Jar; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.configuration.RemapConfigurations; import net.fabricmc.loom.task.AbstractRemapJarTask; +import net.fabricmc.loom.util.Check; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.gradle.SourceSetHelper; @@ -53,7 +53,7 @@ public abstract sealed class MinecraftSourceSets permits MinecraftSourceSets.Sin public void evaluateSplit(Project project) { final LoomGradleExtension extension = LoomGradleExtension.get(project); - Preconditions.checkArgument(extension.areEnvironmentSourceSetsSplit()); + Check.require(extension.areEnvironmentSourceSetsSplit()); Split.INSTANCE.evaluate(project); } @@ -151,9 +151,9 @@ public abstract sealed class MinecraftSourceSets permits MinecraftSourceSets.Sin @Override public void applyDependencies(BiConsumer consumer, List targets) { - Preconditions.checkArgument(targets.size() == 2); - Preconditions.checkArgument(targets.contains(MinecraftJar.Type.COMMON)); - Preconditions.checkArgument(targets.contains(MinecraftJar.Type.CLIENT_ONLY)); + Check.require(targets.size() == 2); + Check.require(targets.contains(MinecraftJar.Type.COMMON)); + Check.require(targets.contains(MinecraftJar.Type.CLIENT_ONLY)); consumer.accept(MINECRAFT_COMMON_NAMED.runtime(), MinecraftJar.Type.COMMON); consumer.accept(MINECRAFT_CLIENT_ONLY_NAMED.runtime(), MinecraftJar.Type.CLIENT_ONLY); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/verify/KnownVersions.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/verify/KnownVersions.java index f585a956..37989180 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/verify/KnownVersions.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/verify/KnownVersions.java @@ -33,9 +33,8 @@ import java.util.Map; import java.util.Objects; import java.util.function.Supplier; -import com.google.common.base.Suppliers; - import net.fabricmc.loom.LoomGradlePlugin; +import net.fabricmc.loom.util.Lazy; /** * The know versions keep track of the versions that are signed using SHA1 or not signature at all. @@ -44,7 +43,7 @@ import net.fabricmc.loom.LoomGradlePlugin; public record KnownVersions( Map client, Map server) { - public static final Supplier INSTANCE = Suppliers.memoize(KnownVersions::load); + public static final Supplier INSTANCE = Lazy.of(KnownVersions::load); private static KnownVersions load() { try (InputStream is = KnownVersions.class.getClassLoader().getResourceAsStream("certs/known_versions.json"); diff --git a/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java b/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java index 7e6493e1..f2846ee2 100644 --- a/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java @@ -36,7 +36,6 @@ import java.util.jar.Manifest; import javax.inject.Inject; -import com.google.common.base.Preconditions; import org.gradle.api.Action; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.RegularFileProperty; @@ -62,6 +61,7 @@ import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.task.service.ClientEntriesService; import net.fabricmc.loom.task.service.JarManifestService; +import net.fabricmc.loom.util.Check; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.ZipReprocessorUtil; import net.fabricmc.loom.util.ZipUtils; @@ -238,7 +238,7 @@ public abstract class AbstractRemapJarTask extends Jar { return out.toByteArray(); })); - Preconditions.checkState(count > 0, "Did not transform any jar manifest"); + Check.require(count > 0, "Did not transform any jar manifest"); } protected void rewriteJar() throws IOException { @@ -259,7 +259,7 @@ public abstract class AbstractRemapJarTask extends Jar { } private SourceSet getClientSourceSet() { - Preconditions.checkArgument(LoomGradleExtension.get(getProject()).areEnvironmentSourceSetsSplit(), "Cannot get client sourceset as project is not split"); + Check.require(LoomGradleExtension.get(getProject()).areEnvironmentSourceSetsSplit(), "Cannot get client sourceset as project is not split"); return SourceSetHelper.getSourceSetByName(getClientOnlySourceSetName().get(), getProject()); } } diff --git a/src/main/java/net/fabricmc/loom/task/LoomTasks.java b/src/main/java/net/fabricmc/loom/task/LoomTasks.java index 8fd96545..7bddb6a9 100644 --- a/src/main/java/net/fabricmc/loom/task/LoomTasks.java +++ b/src/main/java/net/fabricmc/loom/task/LoomTasks.java @@ -28,7 +28,6 @@ import java.io.File; import javax.inject.Inject; -import com.google.common.base.Preconditions; import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.file.FileCollection; @@ -45,6 +44,7 @@ import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; import net.fabricmc.loom.task.launch.GenerateDLIConfigTask; import net.fabricmc.loom.task.launch.GenerateLog4jConfigTask; import net.fabricmc.loom.task.launch.GenerateRemapClasspathTask; +import net.fabricmc.loom.util.Check; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.LoomVersions; import net.fabricmc.loom.util.Platform; @@ -141,7 +141,7 @@ public abstract class LoomTasks implements Runnable { LoomGradleExtension extension = LoomGradleExtension.get(getProject()); final boolean renderDocSupported = RenderDocRunTask.isSupported(Platform.CURRENT); - Preconditions.checkArgument(extension.getRunConfigs().size() == 0, "Run configurations must not be registered before loom"); + Check.require(extension.getRunConfigs().isEmpty(), "Run configurations must not be registered before loom"); extension.getRunConfigs().whenObjectAdded(config -> { var runTask = getTasks().register(getRunConfigTaskName(config), RunGameTask.class, config); diff --git a/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java b/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java index c37ded2c..004209dc 100644 --- a/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java +++ b/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java @@ -27,6 +27,7 @@ package net.fabricmc.loom.task.launch; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -35,7 +36,6 @@ import java.util.Map; import java.util.StringJoiner; import java.util.stream.Collectors; -import org.apache.commons.io.FileUtils; import org.gradle.api.Project; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.logging.configuration.ConsoleOutput; @@ -161,7 +161,7 @@ public abstract class GenerateDLIConfigTask extends AbstractLoomTask { launchConfig.property("fabric.log.disableAnsi", "false"); } - FileUtils.writeStringToFile(getDevLauncherConfig().getAsFile().get(), launchConfig.asString(), StandardCharsets.UTF_8); + Files.writeString(getDevLauncherConfig().getAsFile().get().toPath(), launchConfig.asString(), StandardCharsets.UTF_8); } private static String getAllLog4JConfigFiles(Project project) { diff --git a/src/main/java/net/fabricmc/loom/task/service/LorenzMappingService.java b/src/main/java/net/fabricmc/loom/task/service/LorenzMappingService.java index 40cc1b0b..3d48feb1 100644 --- a/src/main/java/net/fabricmc/loom/task/service/LorenzMappingService.java +++ b/src/main/java/net/fabricmc/loom/task/service/LorenzMappingService.java @@ -28,7 +28,6 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.util.function.Supplier; -import com.google.common.base.Suppliers; import org.cadixdev.lorenz.MappingSet; import org.gradle.api.Project; import org.gradle.api.provider.Property; @@ -37,6 +36,7 @@ import org.gradle.api.tasks.Nested; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration; +import net.fabricmc.loom.util.Lazy; import net.fabricmc.loom.util.service.Service; import net.fabricmc.loom.util.service.ServiceFactory; import net.fabricmc.loom.util.service.ServiceType; @@ -61,7 +61,7 @@ public final class LorenzMappingService extends Service mappings = Suppliers.memoize(this::readMappings); + private final Supplier mappings = Lazy.of(this::readMappings); public LorenzMappingService(Options options, ServiceFactory serviceFactory) { super(options, serviceFactory); diff --git a/src/main/java/net/fabricmc/loom/util/CacheKey.java b/src/main/java/net/fabricmc/loom/util/CacheKey.java index d6fe8ebf..a48c95ae 100644 --- a/src/main/java/net/fabricmc/loom/util/CacheKey.java +++ b/src/main/java/net/fabricmc/loom/util/CacheKey.java @@ -26,7 +26,6 @@ package net.fabricmc.loom.util; import java.util.function.Supplier; -import com.google.common.base.Suppliers; import org.gradle.api.Action; import org.gradle.api.Project; import org.gradle.api.tasks.Internal; @@ -38,8 +37,8 @@ import net.fabricmc.loom.util.gradle.GradleTypeAdapter; */ public abstract class CacheKey { private static final int CHECKSUM_LENGTH = 8; - private final transient Supplier jsonSupplier = Suppliers.memoize(() -> GradleTypeAdapter.GSON.toJson(this)); - private final transient Supplier cacheKeySupplier = Suppliers.memoize(() -> Checksum.of(jsonSupplier.get()).sha1().hex(CHECKSUM_LENGTH)); + private final transient Supplier jsonSupplier = Lazy.of(() -> GradleTypeAdapter.GSON.toJson(this)); + private final transient Supplier cacheKeySupplier = Lazy.of(() -> Checksum.of(jsonSupplier.get()).sha1().hex(CHECKSUM_LENGTH)); public static T create(Project project, Class clazz, Action action) { T instance = project.getObjects().newInstance(clazz); diff --git a/src/main/java/net/fabricmc/loom/util/Check.java b/src/main/java/net/fabricmc/loom/util/Check.java new file mode 100644 index 00000000..6ce9a4e4 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/util/Check.java @@ -0,0 +1,42 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2025 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; + +public final class Check { + private Check() { + } + + public static void require(boolean expression, String message) { + if (!expression) { + throw new IllegalArgumentException(message); + } + } + + public static void require(boolean expression) { + if (!expression) { + throw new IllegalArgumentException(); + } + } +} diff --git a/src/main/java/net/fabricmc/loom/util/DeletingFileVisitor.java b/src/main/java/net/fabricmc/loom/util/DeletingFileVisitor.java index 0bf97022..b65bcbef 100644 --- a/src/main/java/net/fabricmc/loom/util/DeletingFileVisitor.java +++ b/src/main/java/net/fabricmc/loom/util/DeletingFileVisitor.java @@ -32,6 +32,10 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; public class DeletingFileVisitor extends SimpleFileVisitor { + public static void deleteDirectory(Path directory) throws IOException { + Files.walkFileTree(directory, new DeletingFileVisitor()); + } + @Override public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes) throws IOException { Files.delete(path); diff --git a/src/main/java/net/fabricmc/loom/util/Lazy.java b/src/main/java/net/fabricmc/loom/util/Lazy.java new file mode 100644 index 00000000..5c2c0109 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/util/Lazy.java @@ -0,0 +1,66 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2025 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.util.function.Supplier; + +import org.jetbrains.annotations.Nullable; + +// Can be replaced by Lazy Constants (https://openjdk.org/jeps/526) once available. +public final class Lazy { + private Lazy() { + } + + public static Supplier of(Supplier supplier) { + return new Impl<>(supplier); + } + + private static final class Impl implements Supplier { + final Supplier supplier; + + volatile boolean initialized = false; + @Nullable + T value = null; + + private Impl(Supplier supplier) { + this.supplier = supplier; + } + + @Override + public T get() { + // Classic double-checked locking pattern + if (!initialized) { + synchronized (this) { + if (!initialized) { + value = supplier.get(); + initialized = true; + } + } + } + + return value; + } + } +} diff --git a/src/main/java/net/fabricmc/loom/util/LibraryLocationLogger.java b/src/main/java/net/fabricmc/loom/util/LibraryLocationLogger.java index 1d328c57..beab3bc9 100644 --- a/src/main/java/net/fabricmc/loom/util/LibraryLocationLogger.java +++ b/src/main/java/net/fabricmc/loom/util/LibraryLocationLogger.java @@ -26,10 +26,8 @@ package net.fabricmc.loom.util; import java.util.List; -import com.google.common.base.Preconditions; import com.google.gson.Gson; import kotlin.metadata.jvm.KotlinClassMetadata; -import org.apache.commons.io.FileUtils; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.commons.ClassRemapper; import org.objectweb.asm.tree.ClassNode; @@ -52,9 +50,7 @@ public final class LibraryLocationLogger { ClassRemapper.class, ClassNode.class, ASMifier.class, - Gson.class, - Preconditions.class, - FileUtils.class + Gson.class ); private static final Logger LOGGER = LoggerFactory.getLogger(LibraryLocationLogger.class); diff --git a/src/main/java/net/fabricmc/loom/util/gradle/SourceSetReference.java b/src/main/java/net/fabricmc/loom/util/gradle/SourceSetReference.java index 6876446e..9e2ab367 100644 --- a/src/main/java/net/fabricmc/loom/util/gradle/SourceSetReference.java +++ b/src/main/java/net/fabricmc/loom/util/gradle/SourceSetReference.java @@ -24,16 +24,17 @@ package net.fabricmc.loom.util.gradle; -import com.google.common.base.Preconditions; import org.gradle.api.Project; import org.gradle.api.tasks.SourceSet; +import net.fabricmc.loom.util.Check; + /** * A reference to a {@link SourceSet} from a {@link Project}. */ public record SourceSetReference(SourceSet sourceSet, Project project) { public SourceSetReference { - Preconditions.checkArgument( + Check.require( SourceSetHelper.isSourceSetOfProject(sourceSet, project), "SourceSet (%s) does not own to (%s) project".formatted(sourceSet.getName(), project.getName()) );