From 28b8caf8f183363512d7eae4d294cac4e2164151 Mon Sep 17 00:00:00 2001 From: Juuz <6596629+Juuxel@users.noreply.github.com> Date: Sun, 2 Jul 2023 23:38:55 +0300 Subject: [PATCH 1/6] Make resolvable copies of configurations not consumable (#920) This prevents info-level log warnings from mod remapping from flooding the console. --- .../loom/configuration/mods/ModConfigurationRemapper.java | 1 + .../fabricmc/loom/configuration/processors/SpecContextImpl.java | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/java/net/fabricmc/loom/configuration/mods/ModConfigurationRemapper.java b/src/main/java/net/fabricmc/loom/configuration/mods/ModConfigurationRemapper.java index 4aebf75b..7ff0fbc7 100644 --- a/src/main/java/net/fabricmc/loom/configuration/mods/ModConfigurationRemapper.java +++ b/src/main/java/net/fabricmc/loom/configuration/mods/ModConfigurationRemapper.java @@ -96,6 +96,7 @@ public class ModConfigurationRemapper { final Configuration sourceCopy = entry.getSourceConfiguration().get().copyRecursive(); final Usage usage = project.getObjects().named(Usage.class, runtime ? Usage.JAVA_RUNTIME : Usage.JAVA_API); sourceCopy.attributes(attributes -> attributes.attribute(Usage.USAGE_ATTRIBUTE, usage)); + sourceCopy.setCanBeConsumed(false); configsToRemap.put(sourceCopy, target); // If our remap configuration entry targets the client source set as well, diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java b/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java index 9ce71a41..622a0a1c 100644 --- a/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java +++ b/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java @@ -129,6 +129,7 @@ public record SpecContextImpl(List modDependencies, List { final Configuration configuration = settings.getSourceConfiguration().get().copyRecursive(); + configuration.setCanBeConsumed(false); configuration.attributes(attributes -> attributes.attribute(Usage.USAGE_ATTRIBUTE, usage)); return configuration.resolve().stream().map(File::toPath); }; From 8ddf572a7c18954f93d27669ee1248cacc7086ce Mon Sep 17 00:00:00 2001 From: modmuss Date: Sun, 2 Jul 2023 21:39:06 +0100 Subject: [PATCH 2/6] Client annotation processor configuration extendsFrom "annotationProcessor" (#918) --- .../configuration/providers/minecraft/MinecraftSourceSets.java | 3 +++ 1 file changed, 3 insertions(+) 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 c12e1ce3..e28833e2 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 @@ -190,6 +190,9 @@ public abstract sealed class MinecraftSourceSets permits MinecraftSourceSets.Sin extendsFrom(project, MINECRAFT_CLIENT_ONLY_NAMED.runtime(), MINECRAFT_COMMON_NAMED.runtime()); extendsFrom(project, MINECRAFT_CLIENT_ONLY_NAMED.compile(), MINECRAFT_COMMON_NAMED.compile()); + // Client annotation processor configuration extendsFrom "annotationProcessor" + extendsFrom(project, clientOnlySourceSet.getAnnotationProcessorConfigurationName(), JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME); + clientOnlySourceSet.setCompileClasspath( clientOnlySourceSet.getCompileClasspath() .plus(mainSourceSet.getCompileClasspath()) From 6413a9312c0c70cf9b6bf43b5812efc57c54aaae Mon Sep 17 00:00:00 2001 From: modmuss Date: Mon, 3 Jul 2023 17:45:13 +0100 Subject: [PATCH 3/6] Create RunConfigSettings with Gradle's object factory (#917) * Create RunConfigSettings with Gradle's object factory * Update src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java Co-authored-by: Juuz <6596629+Juuxel@users.noreply.github.com> * Update FabricAPI test * Fix version * Actually fix test * Just make the minimal changes for now --------- Co-authored-by: Juuz <6596629+Juuxel@users.noreply.github.com> --- .../configuration/ide/RunConfigSettings.java | 29 +++++++++------ .../extension/LoomGradleExtensionApiImpl.java | 2 +- .../loom/test/LoomTestConstants.groovy | 2 +- .../test/integration/FabricAPITest.groovy | 8 ++-- .../loom/test/util/ServerRunner.groovy | 2 +- src/test/resources/patches/fabric_api.patch | 37 +++---------------- 6 files changed, 30 insertions(+), 50 deletions(-) diff --git a/src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java b/src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java index 82bfeeec..e7d3b39b 100644 --- a/src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java +++ b/src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java @@ -34,6 +34,8 @@ import java.util.Map; import java.util.Objects; import java.util.function.Function; +import javax.inject.Inject; + import org.gradle.api.Named; import org.gradle.api.Project; import org.gradle.api.provider.Property; @@ -45,7 +47,7 @@ import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.Platform; import net.fabricmc.loom.util.gradle.SourceSetHelper; -public final class RunConfigSettings implements Named { +public class RunConfigSettings implements Named { /** * Arguments for the JVM, such as system properties. */ @@ -66,7 +68,7 @@ public final class RunConfigSettings implements Named { * *

By default this is determined from the base name. */ - private String name; + private String configName; /** * The default main class of the run configuration. @@ -97,7 +99,7 @@ public final class RunConfigSettings implements Named { /** * The base name of the run configuration, which is the name it is created with, i.e. 'client' */ - private final String baseName; + private final String name; /** * When true a run configuration file will be generated for IDE's. @@ -111,14 +113,15 @@ public final class RunConfigSettings implements Named { private final Project project; private final LoomGradleExtension extension; - public RunConfigSettings(Project project, String baseName) { - this.baseName = baseName; + @Inject + public RunConfigSettings(Project project, String name) { + this.name = name; this.project = project; this.extension = LoomGradleExtension.get(project); this.ideConfigGenerated = extension.isRootProject(); this.mainClass = project.getObjects().property(String.class).convention(project.provider(() -> { - Objects.requireNonNull(environment, "Run config " + baseName + " must specify environment"); - Objects.requireNonNull(defaultMainClass, "Run config " + baseName + " must specify default main class"); + Objects.requireNonNull(environment, "Run config " + name + " must specify environment"); + Objects.requireNonNull(defaultMainClass, "Run config " + name + " must specify default main class"); return RunConfig.getMainClass(environment, extension, defaultMainClass); })); @@ -140,7 +143,11 @@ public final class RunConfigSettings implements Named { @Override public String getName() { - return baseName; + return name; + } + + public void setName(String name) { + this.configName = name; } public List getVmArgs() { @@ -160,11 +167,11 @@ public final class RunConfigSettings implements Named { } public String getConfigName() { - return name; + return configName; } public void setConfigName(String name) { - this.name = name; + this.configName = name; } public String getDefaultMainClass() { @@ -321,7 +328,7 @@ public final class RunConfigSettings implements Named { environmentVariables.putAll(parent.environmentVariables); environment = parent.environment; - name = parent.name; + configName = parent.configName; defaultMainClass = parent.defaultMainClass; source = parent.source; ideConfigGenerated = parent.ideConfigGenerated; diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java index 17e54ec3..3060d0ef 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java @@ -115,7 +115,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA this.deprecationHelper = new DeprecationHelper.ProjectBased(project); this.runConfigs = project.container(RunConfigSettings.class, - baseName -> new RunConfigSettings(project, baseName)); + baseName -> project.getObjects().newInstance(RunConfigSettings.class, project, baseName)); this.decompilers = project.getObjects().domainObjectContainer(DecompilerOptions.class); this.mods = project.getObjects().domainObjectContainer(ModSettings.class); this.remapConfigurations = project.getObjects().namedDomainObjectList(RemapConfigurationSettings.class); diff --git a/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy b/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy index 1adaaaf2..9aedb1be 100644 --- a/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy @@ -27,7 +27,7 @@ package net.fabricmc.loom.test import org.gradle.util.GradleVersion class LoomTestConstants { - private final static String NIGHTLY_VERSION = "8.3-20230430222526+0000" + private final static String NIGHTLY_VERSION = "8.3-20230702222859+0000" private final static boolean NIGHTLY_EXISTS = nightlyExists(NIGHTLY_VERSION) // Test against the version of Gradle being used to build loom diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/FabricAPITest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/FabricAPITest.groovy index 0ea5b30b..0b20f0a6 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/FabricAPITest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/FabricAPITest.groovy @@ -45,7 +45,7 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait { setup: def gradle = gradleProject( repo: "https://github.com/FabricMC/fabric.git", - commit: "01af69c8709f00b6c1aaf10c3f528fed93a29cfd", + commit: "1ac061308b9d70fa6aad5db3dcc5580cb6ac71cb", version: version, patch: "fabric_api" ) @@ -55,7 +55,7 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait { // Set the version to something constant gradle.buildGradle.text = gradle.buildGradle.text.replace('project.version + "+" + (ENV.GITHUB_RUN_NUMBER ? "" : "local-") + getBranch()', "\"$API_VERSION\"") - def server = ServerRunner.create(gradle.projectDir, "1.19.4") + def server = ServerRunner.create(gradle.projectDir, "1.20.1") .withMod(gradle.getOutputFile("fabric-api-${API_VERSION}.jar")) when: def result = gradle.run(tasks: [ @@ -77,8 +77,8 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait { result.task(":build").outcome == SUCCESS result.task(":prepareRemapJar").outcome == SUCCESS - new File(gradle.mavenLocalDir, "net/fabricmc/fabric-api/fabric-biome-api-v1/13.0.6/fabric-biome-api-v1-13.0.6.jar").exists() - new File(gradle.mavenLocalDir, "net/fabricmc/fabric-api/fabric-biome-api-v1/13.0.6/fabric-biome-api-v1-13.0.6-sources.jar").exists() + new File(gradle.mavenLocalDir, "net/fabricmc/fabric-api/fabric-biome-api-v1/13.0.10/fabric-biome-api-v1-13.0.10.jar").exists() + new File(gradle.mavenLocalDir, "net/fabricmc/fabric-api/fabric-biome-api-v1/13.0.10/fabric-biome-api-v1-13.0.10-sources.jar").exists() serverResult.successful() serverResult.output.contains("- fabric-api $API_VERSION") diff --git a/src/test/groovy/net/fabricmc/loom/test/util/ServerRunner.groovy b/src/test/groovy/net/fabricmc/loom/test/util/ServerRunner.groovy index 4748bedc..2cc9d6f5 100644 --- a/src/test/groovy/net/fabricmc/loom/test/util/ServerRunner.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/util/ServerRunner.groovy @@ -31,7 +31,7 @@ import groovy.transform.Immutable import net.fabricmc.loom.util.download.Download class ServerRunner { - static final String LOADER_VERSION = "0.14.19" + static final String LOADER_VERSION = "0.14.21" static final String INSTALLER_VERSION = "0.11.1" static final Map FABRIC_API_URLS = [ "1.16.5": "https://github.com/FabricMC/fabric/releases/download/0.37.1%2B1.16/fabric-api-0.37.1+1.16.jar", diff --git a/src/test/resources/patches/fabric_api.patch b/src/test/resources/patches/fabric_api.patch index bb6f7077..30d09fef 100644 --- a/src/test/resources/patches/fabric_api.patch +++ b/src/test/resources/patches/fabric_api.patch @@ -1,10 +1,10 @@ diff --git a/build.gradle b/build.gradle ---- a/build.gradle (revision 01af69c8709f00b6c1aaf10c3f528fed93a29cfd) -+++ b/build.gradle (date 1681671870023) -@@ -34,17 +34,7 @@ +--- a/build.gradle (revision 14d319c0729baf781e171e3c9f845fda55670f1b) ++++ b/build.gradle (date 1688330748664) +@@ -37,17 +37,7 @@ throw new NullPointerException("Could not find version for " + project.name) } - + - if (grgit == null) { - return version + "+nogit" - } @@ -18,32 +18,5 @@ diff --git a/build.gradle b/build.gradle - return version + "+" + latestCommits.get(0).id.substring(0, 8) + DigestUtils.sha256Hex(project.rootProject.minecraft_version).substring(0, 2) + return version } - + def getBranch() { -@@ -410,7 +400,7 @@ - productionRuntime { - extendsFrom configurations.minecraftLibraries - extendsFrom configurations.loaderLibraries -- extendsFrom configurations.minecraftRuntimeOnlyLibraries -+ extendsFrom configurations.minecraftRuntimeLibraries - } - productionRuntimeServer - } -@@ -422,8 +412,6 @@ - productionRuntimeServer "net.fabricmc:fabric-installer:${project.installer_version}:server" - } - --import net.fabricmc.loom.util.OperatingSystem -- - // This is very far beyond loom's API if you copy this, you're on your own. - task runProductionAutoTestClient(type: JavaExec, dependsOn: [remapJar, remapTestmodJar]) { - classpath.from configurations.productionRuntime -@@ -444,7 +432,7 @@ - "--gameDir", workingDir.absolutePath - ) - -- if (OperatingSystem.CURRENT_OS == OperatingSystem.MAC_OS) { -+ if (false) { - jvmArgs( - "-XstartOnFirstThread" - ) From e49a051ea02fba72c2e6ffeb757f6709fd391102 Mon Sep 17 00:00:00 2001 From: modmuss Date: Tue, 4 Jul 2023 17:13:48 +0100 Subject: [PATCH 4/6] Fix included none mod libraries not being reproducible. (#923) Closes #921 --- .../build/nesting/IncludedJarFactory.java | 4 +- .../loom/util/ZipReprocessorUtil.java | 74 ++++++++++++++----- .../loom/test/unit/ZipUtilsTest.groovy | 22 ++++++ 3 files changed, 79 insertions(+), 21 deletions(-) diff --git a/src/main/java/net/fabricmc/loom/build/nesting/IncludedJarFactory.java b/src/main/java/net/fabricmc/loom/build/nesting/IncludedJarFactory.java index 4447d7d3..925f5a7c 100644 --- a/src/main/java/net/fabricmc/loom/build/nesting/IncludedJarFactory.java +++ b/src/main/java/net/fabricmc/loom/build/nesting/IncludedJarFactory.java @@ -53,7 +53,7 @@ import org.jetbrains.annotations.Nullable; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.LoomGradlePlugin; import net.fabricmc.loom.task.RemapTaskConfiguration; -import net.fabricmc.loom.util.ZipUtils; +import net.fabricmc.loom.util.ZipReprocessorUtil; import net.fabricmc.loom.util.fmj.FabricModJsonFactory; public final class IncludedJarFactory { @@ -163,7 +163,7 @@ public final class IncludedJarFactory { try { FileUtils.copyFile(input, tempFile); - ZipUtils.add(tempFile.toPath(), "fabric.mod.json", generateModForDependency(metadata).getBytes(StandardCharsets.UTF_8)); + ZipReprocessorUtil.appendZipEntry(tempFile, "fabric.mod.json", generateModForDependency(metadata).getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { throw new UncheckedIOException("Failed to add dummy mod while including %s".formatted(input), e); } diff --git a/src/main/java/net/fabricmc/loom/util/ZipReprocessorUtil.java b/src/main/java/net/fabricmc/loom/util/ZipReprocessorUtil.java index 79f0c872..90d486bc 100644 --- a/src/main/java/net/fabricmc/loom/util/ZipReprocessorUtil.java +++ b/src/main/java/net/fabricmc/loom/util/ZipReprocessorUtil.java @@ -95,44 +95,80 @@ public class ZipReprocessorUtil { return; } - try (ZipFile zipFile = new ZipFile(file)) { + try (var zipFile = new ZipFile(file)) { ZipEntry[] entries; if (reproducibleFileOrder) { - entries = zipFile.stream().sorted(Comparator.comparing(ZipEntry::getName, ZipReprocessorUtil::specialOrdering)).toArray(ZipEntry[]::new); + entries = zipFile.stream() + .sorted(Comparator.comparing(ZipEntry::getName, ZipReprocessorUtil::specialOrdering)) + .toArray(ZipEntry[]::new); } else { - entries = zipFile.stream().toArray(ZipEntry[]::new); + entries = zipFile.stream() + .toArray(ZipEntry[]::new); } - ByteArrayOutputStream outZip = new ByteArrayOutputStream(zipFile.size()); + final var outZip = new ByteArrayOutputStream(entries.length); - try (ZipOutputStream zipOutputStream = new ZipOutputStream(outZip)) { + try (var zipOutputStream = new ZipOutputStream(outZip)) { for (ZipEntry entry : entries) { ZipEntry newEntry = entry; if (!preserveFileTimestamps) { newEntry = new ZipEntry(entry.getName()); - newEntry.setTime(CONSTANT_TIME_FOR_ZIP_ENTRIES); - newEntry.setLastModifiedTime(FileTime.fromMillis(CONSTANT_TIME_FOR_ZIP_ENTRIES)); - newEntry.setLastAccessTime(FileTime.fromMillis(CONSTANT_TIME_FOR_ZIP_ENTRIES)); + setConstantFileTime(newEntry); } - zipOutputStream.putNextEntry(newEntry); - InputStream inputStream = zipFile.getInputStream(entry); - byte[] buf = new byte[1024]; - int length; - - while ((length = inputStream.read(buf)) > 0) { - zipOutputStream.write(buf, 0, length); - } - - zipOutputStream.closeEntry(); + copyZipEntry(zipOutputStream, newEntry, zipFile.getInputStream(entry)); } } - try (FileOutputStream fileOutputStream = new FileOutputStream(file)) { + try (var fileOutputStream = new FileOutputStream(file)) { outZip.writeTo(fileOutputStream); } } } + + public static void appendZipEntry(File file, String path, byte[] data) throws IOException { + try (var zipFile = new ZipFile(file)) { + ZipEntry[] entries = zipFile.stream().toArray(ZipEntry[]::new); + + final var outZip = new ByteArrayOutputStream(entries.length); + + try (var zipOutputStream = new ZipOutputStream(outZip)) { + // Copy existing entries + for (ZipEntry entry : entries) { + copyZipEntry(zipOutputStream, entry, zipFile.getInputStream(entry)); + } + + // Append the new entry + var entry = new ZipEntry(path); + setConstantFileTime(entry); + zipOutputStream.putNextEntry(entry); + zipOutputStream.write(data, 0, data.length); + zipOutputStream.closeEntry(); + } + + try (var fileOutputStream = new FileOutputStream(file)) { + outZip.writeTo(fileOutputStream); + } + } + } + + private static void copyZipEntry(ZipOutputStream zipOutputStream, ZipEntry entry, InputStream inputStream) throws IOException { + zipOutputStream.putNextEntry(entry); + byte[] buf = new byte[1024]; + int length; + + while ((length = inputStream.read(buf)) > 0) { + zipOutputStream.write(buf, 0, length); + } + + zipOutputStream.closeEntry(); + } + + private static void setConstantFileTime(ZipEntry entry) { + entry.setTime(ZipReprocessorUtil.CONSTANT_TIME_FOR_ZIP_ENTRIES); + entry.setLastModifiedTime(FileTime.fromMillis(ZipReprocessorUtil.CONSTANT_TIME_FOR_ZIP_ENTRIES)); + entry.setLastAccessTime(FileTime.fromMillis(ZipReprocessorUtil.CONSTANT_TIME_FOR_ZIP_ENTRIES)); + } } diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/ZipUtilsTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/ZipUtilsTest.groovy index 1c73bed0..95c46916 100644 --- a/src/test/groovy/net/fabricmc/loom/test/unit/ZipUtilsTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/unit/ZipUtilsTest.groovy @@ -29,7 +29,9 @@ import java.nio.file.Files import spock.lang.Specification +import net.fabricmc.loom.util.Checksum import net.fabricmc.loom.util.Pair +import net.fabricmc.loom.util.ZipReprocessorUtil import net.fabricmc.loom.util.ZipUtils class ZipUtilsTest extends Specification { @@ -150,4 +152,24 @@ class ZipUtilsTest extends Specification { then: !result } + + def "append zip entry"() { + given: + // Create a reproducible input zip + def dir = Files.createTempDirectory("loom-zip-test") + def zip = Files.createTempFile("loom-zip-test", ".zip") + def fileInside = dir.resolve("text.txt") + Files.writeString(fileInside, "hello world") + ZipUtils.pack(dir, zip) + ZipReprocessorUtil.reprocessZip(zip.toFile(), true, false) + + when: + // Add an entry to it + ZipReprocessorUtil.appendZipEntry(zip.toFile(), "fabric.mod.json", "Some text".getBytes(StandardCharsets.UTF_8)) + + then: + ZipUtils.unpack(zip, "text.txt") == "hello world".bytes + ZipUtils.unpack(zip, "fabric.mod.json") == "Some text".bytes + Checksum.sha1Hex(zip) == "232ecda4c770bde8ba618e7a194a4f7b57928dc5" + } } From 63eaeed496fde719d2696cfe86f90700b6ebd3e9 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Tue, 4 Jul 2023 17:13:26 +0100 Subject: [PATCH 5/6] Add comment to ZipReprocessorUtil.appendZipEntry --- .../java/net/fabricmc/loom/util/ZipReprocessorUtil.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/net/fabricmc/loom/util/ZipReprocessorUtil.java b/src/main/java/net/fabricmc/loom/util/ZipReprocessorUtil.java index 90d486bc..f1c8c364 100644 --- a/src/main/java/net/fabricmc/loom/util/ZipReprocessorUtil.java +++ b/src/main/java/net/fabricmc/loom/util/ZipReprocessorUtil.java @@ -29,6 +29,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Path; import java.nio.file.attribute.FileTime; import java.util.Calendar; import java.util.Comparator; @@ -128,6 +129,11 @@ public class ZipReprocessorUtil { } } + /** + * Appends an entry to a zip file, persevering the existing entry order and time stamps. + * The new entry is added with a constant time stamp to ensure reproducibility. + * This method should only be used when a reproducible output is required, use {@link ZipUtils#add(Path, String, byte[])} normally. + */ public static void appendZipEntry(File file, String path, byte[] data) throws IOException { try (var zipFile = new ZipFile(file)) { ZipEntry[] entries = zipFile.stream().toArray(ZipEntry[]::new); From cfe72b933a35778fbac05628f7a5111b9219c6e0 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Tue, 4 Jul 2023 17:13:26 +0100 Subject: [PATCH 6/6] Improve Kotlin version detection --- build.gradle | 2 +- .../loom/util/kotlin/KotlinPluginUtils.java | 37 ++++++--------- .../unit/kotlin/KotlinPluginUtilsTest.groovy | 45 ------------------- 3 files changed, 14 insertions(+), 70 deletions(-) delete mode 100644 src/test/groovy/net/fabricmc/loom/test/unit/kotlin/KotlinPluginUtilsTest.groovy diff --git a/build.gradle b/build.gradle index ca293ff2..c7ff152a 100644 --- a/build.gradle +++ b/build.gradle @@ -101,7 +101,7 @@ dependencies { implementation ('net.fabricmc:mercury:0.3.0') // Kotlin - implementation('org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.6.0') { + implementation('org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.6.2') { transitive = false } diff --git a/src/main/java/net/fabricmc/loom/util/kotlin/KotlinPluginUtils.java b/src/main/java/net/fabricmc/loom/util/kotlin/KotlinPluginUtils.java index 3129600c..76a96215 100644 --- a/src/main/java/net/fabricmc/loom/util/kotlin/KotlinPluginUtils.java +++ b/src/main/java/net/fabricmc/loom/util/kotlin/KotlinPluginUtils.java @@ -24,17 +24,16 @@ package net.fabricmc.loom.util.kotlin; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.util.Properties; import kotlinx.metadata.jvm.KotlinClassMetadata; import org.gradle.api.Project; -import org.jetbrains.annotations.VisibleForTesting; public class KotlinPluginUtils { private static final String KOTLIN_PLUGIN_ID = "org.jetbrains.kotlin.jvm"; - private static final Pattern VERSION_PATTERN = Pattern.compile("\\((?.*?)\\)|(?^[^(]*$)"); public static boolean hasKotlinPlugin(Project project) { return project.getPluginManager().hasPlugin(KOTLIN_PLUGIN_ID); @@ -42,30 +41,20 @@ public class KotlinPluginUtils { public static String getKotlinPluginVersion(Project project) { final Class kotlinPluginClass = project.getPlugins().getPlugin(KOTLIN_PLUGIN_ID).getClass(); - /* - 1.7.0-RC-release-217(1.7.0-RC) - 1.6.21-release-334(1.6.21) - 1.9.0-Beta - */ - final String implVersion = kotlinPluginClass.getPackage().getImplementationVersion(); - return parseKotlinVersion(implVersion); + // See KotlinPluginWrapper.loadKotlinPluginVersionFromResourcesOf + return loadPropertyFromResources(kotlinPluginClass, "project.properties", "project.version"); } - @VisibleForTesting - public static String parseKotlinVersion(String implVersion) { - final Matcher matcher = VERSION_PATTERN.matcher(implVersion); + private static String loadPropertyFromResources(Class kotlinPluginClass, String propFileName, String property) { + var props = new Properties(); - if (!matcher.find()) { - throw new IllegalStateException("Unable to match Kotlin version from: " + implVersion); + try (InputStream is = kotlinPluginClass.getClassLoader().getResourceAsStream(propFileName)) { + props.load(is); + } catch (IOException e) { + throw new UncheckedIOException("Failed to read: " + propFileName, e); } - String version = matcher.group("version"); - - if (version == null) { - version = matcher.group("newVersion"); - } - - return Objects.requireNonNull(version); + return props.getProperty(property); } public static String getKotlinMetadataVersion() { diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/kotlin/KotlinPluginUtilsTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/kotlin/KotlinPluginUtilsTest.groovy deleted file mode 100644 index 1ebd22e8..00000000 --- a/src/test/groovy/net/fabricmc/loom/test/unit/kotlin/KotlinPluginUtilsTest.groovy +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2023 FabricMC - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.fabricmc.loom.test.unit.kotlin - -import spock.lang.Specification - -import net.fabricmc.loom.util.kotlin.KotlinPluginUtils - -class KotlinPluginUtilsTest extends Specification { - def "parseKotlinVersion"() { - when: - def parsedVersion = KotlinPluginUtils.parseKotlinVersion(version) - - then: - parsedVersion == expected - - where: - version | expected - "1.7.0-RC-release-217(1.7.0-RC)" | "1.7.0-RC" - "1.6.21-release-334(1.6.21)" | "1.6.21" - "1.9.0-Beta" | "1.9.0-Beta" - } -}