diff --git a/.github/workflows/test-push.yml b/.github/workflows/test-push.yml index 7ef93cc..63458a4 100644 --- a/.github/workflows/test-push.yml +++ b/.github/workflows/test-push.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v2 - uses: gradle/wrapper-validation-action@v1 - - run: gradle build check -x test --stacktrace + - run: gradle build check -x test --stacktrace --warning-mode fail # This job is used to feed the test matrix of next job to allow the tests to run in parallel prepare_test_matrix: @@ -27,7 +27,7 @@ jobs: steps: - uses: actions/checkout@v2 - - run: gradle writeActionsTestMatrix --stacktrace + - run: gradle writeActionsTestMatrix --stacktrace --warning-mode fail - id: set-matrix run: echo "::set-output name=matrix::$(cat build/test_matrix.json)" @@ -51,7 +51,7 @@ jobs: steps: - uses: actions/checkout@v2 - - run: gradle test --tests ${{ matrix.test }} --stacktrace + - run: gradle test --tests ${{ matrix.test }} --stacktrace --warning-mode fail env: TEST_WARNING_MODE: fail @@ -78,7 +78,7 @@ jobs: uses: actions/setup-java@v1 with: java-version: ${{ matrix.java }} - - run: ./gradlew test --tests ${{ matrix.test }} --stacktrace + - run: ./gradlew test --tests ${{ matrix.test }} --stacktrace --warning-mode fail env: TEST_WARNING_MODE: fail @@ -105,7 +105,7 @@ jobs: with: java-version: ${{ matrix.java }} - - run: ./gradlew test --tests *ReproducibleBuildTest --stacktrace + - run: ./gradlew test --tests *ReproducibleBuildTest --stacktrace --warning-mode fail - uses: actions/upload-artifact@v2 if: ${{ failure() }} diff --git a/build.gradle b/build.gradle index 439645f..53b5e1d 100644 --- a/build.gradle +++ b/build.gradle @@ -37,6 +37,9 @@ repositories { url = 'https://maven.fabricmc.net/' } mavenCentral() + maven { + url = 'https://plugins.gradle.org/m2/' + } mavenLocal() } @@ -92,6 +95,9 @@ dependencies { // source code remapping implementation ('net.fabricmc:mercury:0.2.4') + // IDEA support + implementation ('gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext:1.1.1') + // Kapt integration compileOnly('org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0') @@ -162,8 +168,8 @@ jacoco { jacocoTestReport { dependsOn test reports { - xml.enabled false - csv.enabled false + xml.required = false + csv.required = false html.destination file("${buildDir}/jacocoHtml") } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3cd8500..ac0b842 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java index 060a094..5d4e88e 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java @@ -31,6 +31,7 @@ import java.util.function.Supplier; import org.cadixdev.lorenz.MappingSet; import org.cadixdev.mercury.Mercury; +import org.gradle.api.Action; import org.gradle.api.NamedDomainObjectProvider; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; @@ -54,7 +55,12 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { LoomFiles getFiles(); - NamedDomainObjectProvider createLazyConfiguration(String name); + default NamedDomainObjectProvider createLazyConfiguration(String name) { + return createLazyConfiguration(name, config -> { + }); + } + + NamedDomainObjectProvider createLazyConfiguration(String name, Action configurationAction); NamedDomainObjectProvider getLazyConfigurationProvider(String name); @@ -94,10 +100,6 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { boolean isRootProject(); - default boolean ideSync() { - return Boolean.parseBoolean(System.getProperty("idea.sync.active", "false")); - } - default String getIntermediaryUrl(String minecraftVersion) { return String.format(this.getIntermediaryUrl().get(), minecraftVersion); } diff --git a/src/main/java/net/fabricmc/loom/LoomGradlePlugin.java b/src/main/java/net/fabricmc/loom/LoomGradlePlugin.java index 72a9580..096c1b8 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradlePlugin.java +++ b/src/main/java/net/fabricmc/loom/LoomGradlePlugin.java @@ -40,6 +40,7 @@ import net.fabricmc.loom.configuration.CompileConfiguration; import net.fabricmc.loom.configuration.FabricApiExtension; import net.fabricmc.loom.configuration.MavenPublication; import net.fabricmc.loom.configuration.ide.IdeConfiguration; +import net.fabricmc.loom.configuration.ide.idea.IdeaConfiguration; import net.fabricmc.loom.decompilers.DecompilerConfiguration; import net.fabricmc.loom.extension.LoomFiles; import net.fabricmc.loom.extension.LoomGradleExtensionImpl; @@ -84,5 +85,6 @@ public class LoomGradlePlugin implements BootstrappedPlugin { MavenPublication.configure(project); LoomTasks.registerTasks(project); DecompilerConfiguration.setup(project); + IdeaConfiguration.setup(project); } } diff --git a/src/main/java/net/fabricmc/loom/api/mappings/layered/spec/LayeredMappingSpecBuilder.java b/src/main/java/net/fabricmc/loom/api/mappings/layered/spec/LayeredMappingSpecBuilder.java index 1ed527e..f4e5d37 100644 --- a/src/main/java/net/fabricmc/loom/api/mappings/layered/spec/LayeredMappingSpecBuilder.java +++ b/src/main/java/net/fabricmc/loom/api/mappings/layered/spec/LayeredMappingSpecBuilder.java @@ -27,9 +27,10 @@ package net.fabricmc.loom.api.mappings.layered.spec; import groovy.lang.Closure; import groovy.lang.DelegatesTo; import org.gradle.api.Action; -import org.gradle.util.ConfigureUtil; import org.jetbrains.annotations.ApiStatus; +import net.fabricmc.loom.util.ClosureAction; + /** * Used to configure a layered mapping spec. */ @@ -52,7 +53,7 @@ public interface LayeredMappingSpecBuilder { */ @SuppressWarnings("rawtypes") default LayeredMappingSpecBuilder officialMojangMappings(@DelegatesTo(value = MojangMappingsSpecBuilder.class, strategy = Closure.DELEGATE_FIRST) Closure closure) { - return officialMojangMappings(mojangMappingsSpecBuilder -> ConfigureUtil.configure(closure, mojangMappingsSpecBuilder)); + return officialMojangMappings(new ClosureAction<>(closure)); } /** @@ -66,7 +67,7 @@ public interface LayeredMappingSpecBuilder { @SuppressWarnings("rawtypes") default LayeredMappingSpecBuilder parchment(Object object, @DelegatesTo(value = ParchmentMappingsSpecBuilder.class, strategy = Closure.DELEGATE_FIRST) Closure closure) { - return parchment(object, parchmentMappingsSpecBuilder -> ConfigureUtil.configure(closure, parchmentMappingsSpecBuilder)); + return parchment(object, new ClosureAction<>(closure)); } LayeredMappingSpecBuilder parchment(Object object, Action action); diff --git a/src/main/java/net/fabricmc/loom/build/JarRemapper.java b/src/main/java/net/fabricmc/loom/build/JarRemapper.java index 47158bc..877d878 100644 --- a/src/main/java/net/fabricmc/loom/build/JarRemapper.java +++ b/src/main/java/net/fabricmc/loom/build/JarRemapper.java @@ -99,7 +99,7 @@ public class JarRemapper { outputConsumer.addNonClassFiles(data.input); - data.processAccessWidener(remapper.getRemapper()); + data.processAccessWidener(remapper.getEnvironment().getRemapper()); remapper.apply(outputConsumer, data.tag); } diff --git a/src/main/java/net/fabricmc/loom/build/ModCompileRemapper.java b/src/main/java/net/fabricmc/loom/build/ModCompileRemapper.java index 47801d4..d55c689 100644 --- a/src/main/java/net/fabricmc/loom/build/ModCompileRemapper.java +++ b/src/main/java/net/fabricmc/loom/build/ModCompileRemapper.java @@ -29,7 +29,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; -import java.util.zip.ZipFile; import com.google.common.io.Files; import org.gradle.api.Project; @@ -58,6 +57,7 @@ import net.fabricmc.loom.configuration.processors.dependency.ModDependencyInfo; import net.fabricmc.loom.configuration.processors.dependency.RemapData; import net.fabricmc.loom.util.Checksum; import net.fabricmc.loom.util.Constants; +import net.fabricmc.loom.util.ModUtils; import net.fabricmc.loom.util.OperatingSystem; import net.fabricmc.loom.util.SourceRemapper; @@ -91,7 +91,7 @@ public class ModCompileRemapper { String name = artifact.getModuleVersion().getId().getName(); String version = replaceIfNullOrEmpty(artifact.getModuleVersion().getId().getVersion(), () -> Checksum.truncatedSha256(artifact.getFile())); - if (!isFabricMod(logger, artifact.getFile(), artifact.getId())) { + if (!ModUtils.isMod(artifact.getFile())) { addToRegularCompile(project, regularConfig, artifact); continue; } @@ -118,7 +118,7 @@ public class ModCompileRemapper { // Create a mod dependency for each file in the file collection for (File artifact : files) { - if (!isFabricMod(logger, artifact, artifact.getName())) { + if (!ModUtils.isMod(artifact)) { dependencies.add(regularConfig.getName(), project.files(artifact)); continue; } @@ -161,22 +161,6 @@ public class ModCompileRemapper { } } - /** - * Checks if an artifact is a fabric mod, according to the presence of a fabric.mod.json. - */ - private static boolean isFabricMod(Logger logger, File artifact, Object id) { - try (ZipFile zipFile = new ZipFile(artifact)) { - if (zipFile.getEntry("fabric.mod.json") != null) { - logger.info("Found Fabric mod in modCompile: {}", id); - return true; - } - - return false; - } catch (IOException e) { - return false; - } - } - private static void addToRegularCompile(Project project, Configuration regularCompile, ResolvedArtifact artifact) { project.getLogger().info(":providing " + artifact); DependencyHandler dependencies = project.getDependencies(); diff --git a/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java b/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java index f87ccc2..b8203ab 100644 --- a/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java +++ b/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java @@ -39,8 +39,9 @@ import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.ConfigurationContainer; import org.gradle.api.tasks.SourceSet; -import net.fabricmc.loom.extension.MixinExtension; import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.configuration.ide.idea.IdeaUtils; +import net.fabricmc.loom.extension.MixinExtension; import net.fabricmc.loom.util.Constants; /** @@ -97,9 +98,8 @@ public abstract class AnnotationProcessorInvoker { public void configureMixin() { ConfigurationContainer configs = project.getConfigurations(); - LoomGradleExtension extension = LoomGradleExtension.get(project); - if (!extension.ideSync()) { + if (!IdeaUtils.isIdeaSync()) { for (Configuration processorConfig : apConfigurations) { project.getLogger().info("Adding mixin to classpath of AP config: " + processorConfig.getName()); // Pass named MC classpath to mixin AP classpath diff --git a/src/main/java/net/fabricmc/loom/build/mixin/JavaApInvoker.java b/src/main/java/net/fabricmc/loom/build/mixin/JavaApInvoker.java index 770dbda..fbd7293 100644 --- a/src/main/java/net/fabricmc/loom/build/mixin/JavaApInvoker.java +++ b/src/main/java/net/fabricmc/loom/build/mixin/JavaApInvoker.java @@ -58,7 +58,7 @@ public class JavaApInvoker extends AnnotationProcessorInvoker { @Override protected File getRefmapDestinationDir(JavaCompile task) { - return task.getDestinationDir(); + return task.getDestinationDirectory().getAsFile().get(); } private static String getAptConfigurationName(String sourceSet) { diff --git a/src/main/java/net/fabricmc/loom/build/mixin/KaptApInvoker.java b/src/main/java/net/fabricmc/loom/build/mixin/KaptApInvoker.java index 7bf5424..7e3a3ef 100644 --- a/src/main/java/net/fabricmc/loom/build/mixin/KaptApInvoker.java +++ b/src/main/java/net/fabricmc/loom/build/mixin/KaptApInvoker.java @@ -84,7 +84,7 @@ public class KaptApInvoker extends AnnotationProcessorInvoker { try { String refmapName = Objects.requireNonNull(MixinExtension.getMixinInformationContainer(sourceSet)).refmapNameProvider().get(); Path src = Paths.get(getRefmapDestination(task, refmapName)); - Path dest = Paths.get(task.getDestinationDir().toString(), refmapName); + Path dest = Paths.get(task.getDestinationDirectory().get().getAsFile().toString(), refmapName); // Possible that no mixin annotations exist if (Files.exists(src)) { diff --git a/src/main/java/net/fabricmc/loom/build/mixin/ScalaApInvoker.java b/src/main/java/net/fabricmc/loom/build/mixin/ScalaApInvoker.java index e24442e..d361b83 100644 --- a/src/main/java/net/fabricmc/loom/build/mixin/ScalaApInvoker.java +++ b/src/main/java/net/fabricmc/loom/build/mixin/ScalaApInvoker.java @@ -59,6 +59,6 @@ public class ScalaApInvoker extends AnnotationProcessorInvoker { @Override protected File getRefmapDestinationDir(ScalaCompile task) { - return task.getDestinationDir(); + return task.getDestinationDirectory().get().getAsFile(); } } diff --git a/src/main/java/net/fabricmc/loom/build/nesting/NestedDependencyProvider.java b/src/main/java/net/fabricmc/loom/build/nesting/NestedDependencyProvider.java index 18dc816..a911d30 100644 --- a/src/main/java/net/fabricmc/loom/build/nesting/NestedDependencyProvider.java +++ b/src/main/java/net/fabricmc/loom/build/nesting/NestedDependencyProvider.java @@ -53,6 +53,7 @@ import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.LoomGradlePlugin; import net.fabricmc.loom.task.RemapJarTask; import net.fabricmc.loom.util.Constants; +import net.fabricmc.loom.util.ModUtils; import net.fabricmc.loom.util.ZipUtils; public final class NestedDependencyProvider implements NestedJarProvider { @@ -158,7 +159,7 @@ public final class NestedDependencyProvider implements NestedJarProvider { File file = metaFile.file; //A lib that doesnt have a mod.json, we turn it into a fake mod - if (!ZipUtils.contains(file.toPath(), "fabric.mod.json")) { + if (!ModUtils.isMod(file)) { LoomGradleExtension extension = LoomGradleExtension.get(project); File tempDir = new File(extension.getFiles().getUserCache(), "temp/modprocessing"); diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index f99d721..74abad3 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -26,9 +26,11 @@ package net.fabricmc.loom.configuration; import java.nio.charset.StandardCharsets; +import org.gradle.api.NamedDomainObjectProvider; import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.tasks.AbstractCopyTask; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.compile.JavaCompile; @@ -39,7 +41,6 @@ import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.build.mixin.JavaApInvoker; import net.fabricmc.loom.build.mixin.KaptApInvoker; import net.fabricmc.loom.build.mixin.ScalaApInvoker; -import net.fabricmc.loom.configuration.ide.SetupIntelijRunConfigs; import net.fabricmc.loom.configuration.providers.LaunchProvider; import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; @@ -53,15 +54,20 @@ public final class CompileConfiguration { public static void setupConfigurations(Project project) { LoomGradleExtension extension = LoomGradleExtension.get(project); - extension.createLazyConfiguration(Constants.Configurations.MOD_COMPILE_CLASSPATH).configure(configuration -> configuration.setTransitive(true)); - extension.createLazyConfiguration(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED).configure(configuration -> configuration.setTransitive(false)); - extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_NAMED).configure(configuration -> configuration.setTransitive(false)); // The launchers do not recurse dependencies - extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_DEPENDENCIES).configure(configuration -> configuration.setTransitive(false)); - extension.createLazyConfiguration(Constants.Configurations.LOADER_DEPENDENCIES).configure(configuration -> configuration.setTransitive(false)); - extension.createLazyConfiguration(Constants.Configurations.MINECRAFT).configure(configuration -> configuration.setTransitive(false)); - extension.createLazyConfiguration(Constants.Configurations.INCLUDE).configure(configuration -> configuration.setTransitive(false)); // Dont get transitive deps + extension.createLazyConfiguration(Constants.Configurations.MOD_COMPILE_CLASSPATH, configuration -> configuration.setTransitive(true)); + extension.createLazyConfiguration(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED, configuration -> configuration.setTransitive(false)); + extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_NAMED, configuration -> configuration.setTransitive(false)); // The launchers do not recurse dependencies + NamedDomainObjectProvider serverDeps = extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_SERVER_DEPENDENCIES, configuration -> configuration.setTransitive(false)); + extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_DEPENDENCIES, configuration -> { + configuration.extendsFrom(serverDeps.get()); + configuration.setTransitive(false); + }); + extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_NATIVES, configuration -> configuration.setTransitive(false)); + extension.createLazyConfiguration(Constants.Configurations.LOADER_DEPENDENCIES, configuration -> configuration.setTransitive(false)); + extension.createLazyConfiguration(Constants.Configurations.MINECRAFT, configuration -> configuration.setTransitive(false)); + extension.createLazyConfiguration(Constants.Configurations.INCLUDE, configuration -> configuration.setTransitive(false)); // Dont get transitive deps extension.createLazyConfiguration(Constants.Configurations.MAPPING_CONSTANTS); - extension.createLazyConfiguration(Constants.Configurations.NAMED_ELEMENTS).configure(configuration -> { + extension.createLazyConfiguration(Constants.Configurations.NAMED_ELEMENTS, configuration -> { configuration.setCanBeConsumed(true); configuration.setCanBeResolved(false); configuration.extendsFrom(project.getConfigurations().getByName(JavaPlugin.API_CONFIGURATION_NAME)); @@ -117,9 +123,9 @@ public final class CompileConfiguration { } public static void configureCompile(Project p) { - JavaPluginConvention javaModule = (JavaPluginConvention) p.getConvention().getPlugins().get("java"); + final JavaPluginExtension javaPluginExtension = p.getExtensions().getByType(JavaPluginExtension.class); - SourceSet main = javaModule.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME); + SourceSet main = javaPluginExtension.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME); Javadoc javadoc = (Javadoc) p.getTasks().getByName(JavaPlugin.JAVADOC_TASK_NAME); javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath())); @@ -140,7 +146,6 @@ public final class CompileConfiguration { project.getTasks().getByName("eclipse").finalizedBy(project.getTasks().getByName("genEclipseRuns")); project.getTasks().getByName("cleanEclipse").finalizedBy(project.getTasks().getByName("cleanEclipseRuns")); - SetupIntelijRunConfigs.setup(project); extension.getRemapArchives().finalizeValue(); // Enables the default mod remapper diff --git a/src/main/java/net/fabricmc/loom/configuration/LoomDependencyManager.java b/src/main/java/net/fabricmc/loom/configuration/LoomDependencyManager.java index 29ae1d0..7f92402 100644 --- a/src/main/java/net/fabricmc/loom/configuration/LoomDependencyManager.java +++ b/src/main/java/net/fabricmc/loom/configuration/LoomDependencyManager.java @@ -46,6 +46,7 @@ import net.fabricmc.loom.LoomGradlePlugin; import net.fabricmc.loom.LoomRepositoryPlugin; import net.fabricmc.loom.build.ModCompileRemapper; import net.fabricmc.loom.configuration.DependencyProvider.DependencyInfo; +import net.fabricmc.loom.configuration.ide.idea.IdeaUtils; import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.SourceRemapper; @@ -209,7 +210,7 @@ public class LoomDependencyManager { loaderDepsConfig.getDependencies().add(modDep); // TODO: work around until https://github.com/FabricMC/Mixin/pull/60 and https://github.com/FabricMC/fabric-mixin-compile-extensions/issues/14 is fixed. - if (!extension.ideSync() && extension.getMixin().getUseLegacyMixinAp().get()) { + if (!IdeaUtils.isIdeaSync() && extension.getMixin().getUseLegacyMixinAp().get()) { apDepsConfig.getDependencies().add(modDep); } diff --git a/src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerJarProcessor.java b/src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerJarProcessor.java index d5f234b..1305de7 100644 --- a/src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerJarProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerJarProcessor.java @@ -152,7 +152,7 @@ public class TransitiveAccessWidenerJarProcessor implements JarProcessor { try { AccessWidenerRemapper remappingVisitor = new AccessWidenerRemapper( accessWidener, - tinyRemapper.getRemapper(), + tinyRemapper.getEnvironment().getRemapper(), MappingsNamespace.INTERMEDIARY.toString(), MappingsNamespace.NAMED.toString() ); diff --git a/src/main/java/net/fabricmc/loom/configuration/ide/RunConfig.java b/src/main/java/net/fabricmc/loom/configuration/ide/RunConfig.java index 3e23dec..3d1b4a0 100644 --- a/src/main/java/net/fabricmc/loom/configuration/ide/RunConfig.java +++ b/src/main/java/net/fabricmc/loom/configuration/ide/RunConfig.java @@ -45,6 +45,7 @@ import org.w3c.dom.Node; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.configuration.InstallerData; +import net.fabricmc.loom.configuration.ide.idea.IdeaSyncTask; public class RunConfig { public String configName; @@ -174,7 +175,7 @@ public class RunConfig { public String fromDummy(String dummy, boolean relativeDir, Project project) throws IOException { String dummyConfig; - try (InputStream input = SetupIntelijRunConfigs.class.getClassLoader().getResourceAsStream(dummy)) { + try (InputStream input = IdeaSyncTask.class.getClassLoader().getResourceAsStream(dummy)) { dummyConfig = new String(input.readAllBytes(), StandardCharsets.UTF_8); } 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 a7a1c42..81f24a2 100644 --- a/src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java +++ b/src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java @@ -34,7 +34,7 @@ import java.util.function.Function; import org.gradle.api.Named; import org.gradle.api.Project; -import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.tasks.SourceSet; import net.fabricmc.loom.LoomGradleExtension; @@ -229,10 +229,7 @@ public final class RunConfigSettings implements Named { } public void source(String source) { - setSource(proj -> { - JavaPluginConvention conv = proj.getConvention().getPlugin(JavaPluginConvention.class); - return conv.getSourceSets().getByName(source); - }); + setSource(proj -> project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets().getByName(source)); } public void ideConfigGenerated(boolean ideConfigGenerated) { @@ -243,7 +240,7 @@ public final class RunConfigSettings implements Named { * Add the {@code -XstartOnFirstThread} JVM argument when on OSX. */ public void startFirstThread() { - if (OperatingSystem.getOS().equalsIgnoreCase("osx")) { + if (OperatingSystem.CURRENT_OS.equals(OperatingSystem.MAC_OS)) { vmArg("-XstartOnFirstThread"); } } diff --git a/src/main/java/net/fabricmc/loom/configuration/ide/SetupIntelijRunConfigs.java b/src/main/java/net/fabricmc/loom/configuration/ide/SetupIntelijRunConfigs.java deleted file mode 100644 index 8120a63..0000000 --- a/src/main/java/net/fabricmc/loom/configuration/ide/SetupIntelijRunConfigs.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2016-2021 FabricMC - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.fabricmc.loom.configuration.ide; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; - -import org.apache.commons.io.FileUtils; -import org.gradle.api.Project; - -import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.configuration.providers.minecraft.MinecraftNativesProvider; -import net.fabricmc.loom.configuration.providers.minecraft.assets.MinecraftAssetsProvider; - -public class SetupIntelijRunConfigs { - public static void setup(Project project) { - File projectDir = project.getRootProject().file(".idea"); - - if (!projectDir.exists()) { - return; - } - - try { - generate(project); - } catch (IOException e) { - throw new RuntimeException("Failed to generate run configs", e); - } - } - - private static void generate(Project project) throws IOException { - Project rootProject = project.getRootProject(); - LoomGradleExtension extension = LoomGradleExtension.get(project); - - if (extension.ideSync()) { - //Ensures the assets are downloaded when idea is syncing a project - MinecraftAssetsProvider.provide(extension.getMinecraftProvider(), project); - MinecraftNativesProvider.provide(project); - } - - String projectPath = project == rootProject ? "" : project.getPath().replace(':', '_'); - - File projectDir = rootProject.file(".idea"); - File runConfigsDir = new File(projectDir, "runConfigurations"); - - if (!runConfigsDir.exists()) { - runConfigsDir.mkdirs(); - } - - for (RunConfigSettings settings : extension.getRunConfigs()) { - if (!settings.isIdeConfigGenerated()) { - continue; - } - - RunConfig config = RunConfig.runConfig(project, settings); - String name = config.configName.replaceAll("[^a-zA-Z0-9$_]", "_"); - - File runConfigs = new File(runConfigsDir, name + projectPath + ".xml"); - String runConfigXml = config.fromDummy("idea_run_config_template.xml", true, project); - - if (!runConfigs.exists()) { - FileUtils.writeStringToFile(runConfigs, runConfigXml, StandardCharsets.UTF_8); - } - - settings.makeRunDir(); - } - } -} diff --git a/src/main/java/net/fabricmc/loom/configuration/ide/idea/IdeaConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/ide/idea/IdeaConfiguration.java new file mode 100644 index 0000000..17a646d --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/ide/idea/IdeaConfiguration.java @@ -0,0 +1,83 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.configuration.ide.idea; + +import java.util.Objects; + +import org.gradle.api.NamedDomainObjectContainer; +import org.gradle.api.Project; +import org.gradle.api.plugins.ExtensionAware; +import org.gradle.api.tasks.TaskProvider; +import org.gradle.plugins.ide.idea.model.IdeaModel; +import org.gradle.plugins.ide.idea.model.IdeaProject; +import org.jetbrains.gradle.ext.ActionDelegationConfig; +import org.jetbrains.gradle.ext.IdeaExtPlugin; +import org.jetbrains.gradle.ext.ProjectSettings; +import org.jetbrains.gradle.ext.RunConfiguration; +import org.jetbrains.gradle.ext.TaskTriggersConfig; + +public class IdeaConfiguration { + public static void setup(Project project) { + TaskProvider ideaSyncTask = project.getTasks().register("ideaSyncTask", IdeaSyncTask.class, ideaSyncTask1 -> { + ideaSyncTask1.dependsOn(project.getTasks().named("downloadAssets")); + }); + + if (!IdeaUtils.isIdeaSync()) { + return; + } + + project.getPlugins().apply(IdeaExtPlugin.class); + project.getPlugins().withType(IdeaExtPlugin.class, ideaExtPlugin -> { + if (project != project.getRootProject()) { + // Also ensure it's applied to the root project. + project.getRootProject().getPlugins().apply(IdeaExtPlugin.class); + } + + final IdeaModel ideaModel = project.getRootProject().getExtensions().findByType(IdeaModel.class); + + if (ideaModel == null) { + return; + } + + final IdeaProject ideaProject = ideaModel.getProject(); + + if (ideaProject == null) { + return; + } + + final ProjectSettings settings = getExtension(ideaProject, ProjectSettings.class); + final ActionDelegationConfig delegateActions = getExtension(settings, ActionDelegationConfig.class); + final TaskTriggersConfig taskTriggers = getExtension(settings, TaskTriggersConfig.class); + final NamedDomainObjectContainer runConfigurations = (NamedDomainObjectContainer) ((ExtensionAware) settings).getExtensions().getByName("runConfigurations"); + + // Run the sync task on import + taskTriggers.afterSync(ideaSyncTask); + }); + } + + private static T getExtension(Object extensionAware, Class type) { + return Objects.requireNonNull(((ExtensionAware) extensionAware).getExtensions().getByType(type)); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/ide/idea/IdeaSyncTask.java b/src/main/java/net/fabricmc/loom/configuration/ide/idea/IdeaSyncTask.java new file mode 100644 index 0000000..58a4224 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/ide/idea/IdeaSyncTask.java @@ -0,0 +1,130 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.configuration.ide.idea; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import javax.inject.Inject; + +import org.apache.commons.io.FileUtils; +import org.gradle.api.Project; +import org.gradle.api.tasks.TaskAction; + +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.configuration.ide.RunConfig; +import net.fabricmc.loom.configuration.ide.RunConfigSettings; +import net.fabricmc.loom.configuration.providers.BundleMetadata; +import net.fabricmc.loom.task.AbstractLoomTask; +import net.fabricmc.loom.util.Constants; + +public abstract class IdeaSyncTask extends AbstractLoomTask { + @Inject + public IdeaSyncTask() { + // Always re-run this task. + getOutputs().upToDateWhen(element -> false); + } + + @TaskAction + public void runTask() throws IOException { + File projectDir = getProject().getRootProject().file(".idea"); + + if (!projectDir.exists()) { + throw new RuntimeException("No .idea directory found"); + } + + generateRunConfigs(); + } + + // See: https://github.com/FabricMC/fabric-loom/pull/206#issuecomment-986054254 for the reason why XML's are still used to provide the run configs + private void generateRunConfigs() throws IOException { + Project rootProject = getProject().getRootProject(); + LoomGradleExtension extension = LoomGradleExtension.get(getProject()); + String projectPath = getProject() == rootProject ? "" : getProject().getPath().replace(':', '_'); + File runConfigsDir = new File(rootProject.file(".idea"), "runConfigurations"); + + if (!runConfigsDir.exists()) { + runConfigsDir.mkdirs(); + } + + final List excludedServerLibraries = getExcludedServerLibraries(); + + for (RunConfigSettings settings : extension.getRunConfigs()) { + if (!settings.isIdeConfigGenerated()) { + continue; + } + + RunConfig config = RunConfig.runConfig(getProject(), settings); + String name = config.configName.replaceAll("[^a-zA-Z0-9$_]", "_"); + + File runConfigs = new File(runConfigsDir, name + projectPath + ".xml"); + String runConfigXml = config.fromDummy("idea_run_config_template.xml", true, getProject()); + + if (!runConfigs.exists()) { + FileUtils.writeStringToFile(runConfigs, runConfigXml, StandardCharsets.UTF_8); + } + + settings.makeRunDir(); + + if (settings.getEnvironment().equals("server") && !excludedServerLibraries.isEmpty()) { + try { + setClasspathModifications(runConfigs, excludedServerLibraries); + } catch (Exception e) { + getProject().getLogger().error("Failed to modify run configuration xml", e); + } + } + } + } + + private List getExcludedServerLibraries() { + final BundleMetadata bundleMetadata = getExtension().getMinecraftProvider().getServerBundleMetadata(); + + if (bundleMetadata == null) { + // Legacy version + return Collections.emptyList(); + } + + final Set allLibraries = getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES).getFiles(); + final Set serverLibraries = getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_SERVER_DEPENDENCIES).getFiles(); + final List clientOnlyLibraries = new LinkedList<>(); + + for (File commonLibrary : allLibraries) { + if (!serverLibraries.contains(commonLibrary)) { + clientOnlyLibraries.add(commonLibrary.getAbsolutePath()); + } + } + + return clientOnlyLibraries; + } + + private void setClasspathModifications(File runConfig, List exclusions) throws Exception { + // TODO modify the xml + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/ide/idea/IdeaUtils.java b/src/main/java/net/fabricmc/loom/configuration/ide/idea/IdeaUtils.java new file mode 100644 index 0000000..e1aa3ea --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/ide/idea/IdeaUtils.java @@ -0,0 +1,45 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.configuration.ide.idea; + +import java.util.Objects; + +public class IdeaUtils { + public static boolean isIdeaSync() { + return Boolean.parseBoolean(System.getProperty("idea.sync.active", "false")); + } + + public static String getIdeaVersion() { + return Objects.requireNonNull(System.getProperty("idea.version"), "Could not get idea version"); + } + + // 2021.3 or newer + public static boolean supportsCustomizableClasspath() { + final String[] split = getIdeaVersion().split("\\."); + final int major = Integer.parseInt(split[0]); + final int minor = Integer.parseInt(split[1]); + return major > 2021 || (major == 2021 && minor >= 3); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/mods/ModVersionParser.java b/src/main/java/net/fabricmc/loom/configuration/mods/ModVersionParser.java index 09c4fc1..983bc1e 100644 --- a/src/main/java/net/fabricmc/loom/configuration/mods/ModVersionParser.java +++ b/src/main/java/net/fabricmc/loom/configuration/mods/ModVersionParser.java @@ -30,7 +30,7 @@ import java.io.IOException; import com.google.gson.JsonObject; import org.gradle.api.Project; -import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.plugins.JavaPluginExtension; import net.fabricmc.loom.LoomGradlePlugin; @@ -67,7 +67,7 @@ public class ModVersionParser { } private File locateModJsonFile() { - return project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets() + return project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets() .getByName("main") .getResources() .matching(patternFilterable -> patternFilterable.include("fabric.mod.json")) diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/BundleMetadata.java b/src/main/java/net/fabricmc/loom/configuration/providers/BundleMetadata.java new file mode 100644 index 0000000..aa6b937 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/BundleMetadata.java @@ -0,0 +1,93 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.configuration.providers; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.loom.util.FileSystemUtil; + +public record BundleMetadata(List libraries, List versions, String mainClass) { + private static final String LIBRARIES_LIST_PATH = "META-INF/libraries.list"; + private static final String VERSIONS_LIST_PATH = "META-INF/versions.list"; + private static final String MAINCLASS_PATH = "META-INF/main-class"; + + @Nullable + public static BundleMetadata fromJar(Path jar) throws IOException { + final List libraries; + final List versions; + final String mainClass; + + try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(jar)) { + if (!Files.exists(fs.get().getPath(VERSIONS_LIST_PATH))) { + // Legacy jar + return null; + } + + libraries = readEntries(fs.readString(LIBRARIES_LIST_PATH), "META-INF/libraries/"); + versions = readEntries(fs.readString(VERSIONS_LIST_PATH), "META-INF/versions/"); + mainClass = fs.readString(MAINCLASS_PATH).trim(); + } + + return new BundleMetadata(libraries, versions, mainClass); + } + + private static List readEntries(String content, String pathPrefix) { + List entries = new ArrayList<>(); + + for (String entry : content.split("\n")) { + if (entry.isBlank()) { + continue; + } + + String[] split = entry.split("\t"); + + if (split.length != 3) { + continue; + } + + entries.add(new Entry(split[0], split[1], pathPrefix + split[2])); + } + + return Collections.unmodifiableList(entries); + } + + public record Entry(String sha1, String name, String path) { + public void unpackEntry(Path jar, Path dest) throws IOException { + try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(jar); + InputStream is = Files.newInputStream(fs.get().getPath(path()))) { + Files.copy(is, dest, StandardCopyOption.REPLACE_EXISTING); + } + } + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java index 312492a..fcfa226 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java @@ -54,13 +54,15 @@ public class LaunchProvider extends DependencyProvider { @Override public void provide(DependencyInfo dependency, Consumer postPopulationScheduler) throws IOException { + final String nativesPath = getExtension().getFiles().getNativesDirectory(getProject()).getAbsolutePath(); + final LaunchConfig launchConfig = new LaunchConfig() .property("fabric.development", "true") .property("fabric.remapClasspathFile", getRemapClasspathFile().getAbsolutePath()) .property("log4j.configurationFile", getAllLog4JConfigFiles()) - .property("client", "java.library.path", getExtension().getMinecraftProvider().nativesDir().getAbsolutePath()) - .property("client", "org.lwjgl.librarypath", getExtension().getMinecraftProvider().nativesDir().getAbsolutePath()) + .property("client", "java.library.path", nativesPath) + .property("client", "org.lwjgl.librarypath", nativesPath) .argument("client", "--assetIndex") .argument("client", getExtension().getMinecraftProvider().getVersionInfo().assetIndex().fabricId(getExtension().getMinecraftProvider().minecraftVersion())) diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProvider.java index 9659319..d8e4a77 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProvider.java @@ -31,10 +31,6 @@ import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; public interface MinecraftProvider { File workingDir(); - boolean hasCustomNatives(); - - File nativesDir(); - File dir(String path); File file(String path); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProviderImpl.java b/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProviderImpl.java index 4cda3be..de895de 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProviderImpl.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProviderImpl.java @@ -27,20 +27,16 @@ package net.fabricmc.loom.configuration.providers; import java.io.File; import java.io.FileReader; import java.io.IOException; -import java.io.InputStream; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.nio.file.StandardCopyOption; -import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; import com.google.common.io.Files; import org.gradle.api.GradleException; import org.gradle.api.Project; import org.gradle.api.logging.Logger; +import org.jetbrains.annotations.Nullable; import net.fabricmc.loom.LoomGradlePlugin; import net.fabricmc.loom.configuration.DependencyProvider; @@ -48,9 +44,9 @@ import net.fabricmc.loom.configuration.providers.minecraft.ManifestVersion; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftLibraryProvider; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; import net.fabricmc.loom.util.Constants; -import net.fabricmc.loom.util.MirrorUtil; import net.fabricmc.loom.util.DownloadUtil; import net.fabricmc.loom.util.HashedDownloadUtil; +import net.fabricmc.loom.util.MirrorUtil; import net.fabricmc.stitch.merge.JarMerger; public class MinecraftProviderImpl extends DependencyProvider implements MinecraftProvider { @@ -66,6 +62,8 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra private File minecraftServerJar; // The extracted server jar from the boostrap, only exists in >=21w39a private File minecraftExtractedServerJar; + @Nullable + private BundleMetadata serverBundleMetadata; private File minecraftMergedJar; private File versionManifestJson; private File experimentalVersionsJson; @@ -101,6 +99,8 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra downloadJars(getProject().getLogger()); } + serverBundleMetadata = BundleMetadata.fromJar(minecraftServerJar.toPath()); + libraryProvider = new MinecraftLibraryProvider(); libraryProvider.provide(this, getProject()); @@ -257,61 +257,22 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra private void mergeJars(Logger logger) throws IOException { logger.info(":merging jars"); - try (JarMerger jarMerger = new JarMerger(minecraftClientJar, getServerJarToMerge(logger), minecraftMergedJar)) { - jarMerger.enableSyntheticParamsOffset(); - jarMerger.merge(); - } - } - - private File getServerJarToMerge(Logger logger) throws IOException { - try (ZipFile zipFile = new ZipFile(minecraftServerJar)) { - ZipEntry versionsListEntry = zipFile.getEntry("META-INF/versions.list"); - - if (versionsListEntry == null) { - // Legacy pre 21w38a jar - return minecraftServerJar; - } + File jarToMerge = minecraftServerJar; + if (serverBundleMetadata != null) { logger.info(":Extracting server jar from bootstrap"); - String versionsList; - - try (InputStream is = zipFile.getInputStream(versionsListEntry)) { - versionsList = new String(is.readAllBytes(), StandardCharsets.UTF_8); + if (serverBundleMetadata.versions().size() != 1) { + throw new UnsupportedOperationException("Expected only 1 version in META-INF/versions.list, but got %d".formatted(serverBundleMetadata.versions().size())); } - String jarPath = null; - String[] versions = versionsList.split("\n"); + serverBundleMetadata.versions().get(0).unpackEntry(minecraftServerJar.toPath(), minecraftExtractedServerJar.toPath()); + jarToMerge = minecraftExtractedServerJar; + } - if (versions.length != 1) { - throw new UnsupportedOperationException("Expected only 1 version in META-INF/versions.list, but got %d".formatted(versions.length)); - } - - for (String version : versions) { - if (version.isBlank()) continue; - - String[] split = version.split("\t"); - - if (split.length != 3) continue; - - final String hash = split[0]; - final String id = split[1]; - final String path = split[2]; - - // Take the first (only) version we find. - jarPath = path; - break; - } - - Objects.requireNonNull(jarPath, "Could not find minecraft server jar for " + minecraftVersion()); - ZipEntry serverJarEntry = zipFile.getEntry("META-INF/versions/" + jarPath); - Objects.requireNonNull(serverJarEntry, "Could not find server jar in boostrap@ " + jarPath); - - try (InputStream is = zipFile.getInputStream(serverJarEntry)) { - java.nio.file.Files.copy(is, minecraftExtractedServerJar.toPath(), StandardCopyOption.REPLACE_EXISTING); - } - - return minecraftExtractedServerJar; + try (JarMerger jarMerger = new JarMerger(minecraftClientJar, jarToMerge, minecraftMergedJar)) { + jarMerger.enableSyntheticParamsOffset(); + jarMerger.merge(); } } @@ -324,20 +285,6 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra return workingDir; } - @Override - public boolean hasCustomNatives() { - return getProject().getProperties().get("fabric.loom.natives.dir") != null; - } - - @Override - public File nativesDir() { - if (hasCustomNatives()) { - return new File((String) getProject().property("fabric.loom.natives.dir")); - } - - return dir("natives"); - } - @Override public File dir(String path) { File dir = file(path); @@ -368,4 +315,9 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra public String getTargetConfig() { return Constants.Configurations.MINECRAFT; } + + @Nullable + public BundleMetadata getServerBundleMetadata() { + return serverBundleMetadata; + } } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/LWJGLVersionOverride.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/LWJGLVersionOverride.java new file mode 100644 index 0000000..9471caf --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/LWJGLVersionOverride.java @@ -0,0 +1,108 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.configuration.providers.minecraft; + +import static net.fabricmc.loom.util.OperatingSystem.LINUX; +import static net.fabricmc.loom.util.OperatingSystem.MAC_OS; +import static net.fabricmc.loom.util.OperatingSystem.WINDOWS; + +import java.util.List; + +import org.gradle.api.Project; +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.loom.util.Architecture; +import net.fabricmc.loom.util.OperatingSystem; + +public class LWJGLVersionOverride { + public static final String LWJGL_VERSION = "3.3.0"; + @Nullable + public static final String NATIVE_CLASSIFIER = getNativesClassifier(); + + public static final List DEPENDENCIES = List.of( + "org.lwjgl:lwjgl:" + LWJGL_VERSION, + "org.lwjgl:lwjgl-glfw:" + LWJGL_VERSION, + "org.lwjgl:lwjgl-jemalloc:" + LWJGL_VERSION, + "org.lwjgl:lwjgl-openal:" + LWJGL_VERSION, + "org.lwjgl:lwjgl-opengl:" + LWJGL_VERSION, + "org.lwjgl:lwjgl-stb:" + LWJGL_VERSION, + "org.lwjgl:lwjgl-tinyfd:" + LWJGL_VERSION + ); + public static final List NATIVES = DEPENDENCIES.stream().map(s -> s + ":" + NATIVE_CLASSIFIER).toList(); + + /** + * Update lwjgl by default when running on arm and a supported configuration. + */ + public static boolean overrideByDefault() { + return NATIVE_CLASSIFIER != null && Architecture.CURRENT.isArm(); + } + + public static boolean forceOverride(Project project) { + return project.getProperties().get("fabric.loom.override-lwjgl") != null; + } + + @Nullable + private static String getNativesClassifier() { + return switch (OperatingSystem.CURRENT_OS) { + case WINDOWS -> getWindowsClassifier(); + case MAC_OS -> getMacOSClassifier(); + case LINUX -> getLinuxClassifier(); + default -> null; + }; + } + + private static String getWindowsClassifier() { + if (Architecture.CURRENT.is64Bit()) { + if (Architecture.CURRENT.isArm()) { + // Arm 64 bit + return "natives-windows-arm64"; + } + + // None arm 64bit + return "natives-windows"; + } + + // All 32bit, including arm + return "natives-windows-x86"; + } + + private static String getMacOSClassifier() { + if (Architecture.CURRENT.isArm()) { + // Apple silicone arm + return "natives-macos-arm64"; + } + + // Intel 64bit. + return "natives-macos"; + } + + private static String getLinuxClassifier() { + if (Architecture.CURRENT.isArm()) { + return Architecture.CURRENT.is64Bit() ? "natives-linux-arm64" : "natives-linux-arm32"; + } + + return "natives-linux"; + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java index 53c9412..3e4a3c4 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java @@ -24,31 +24,77 @@ package net.fabricmc.loom.configuration.providers.minecraft; -import java.io.File; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.gradle.api.Project; +import org.gradle.api.artifacts.ExternalModuleDependency; -import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.configuration.providers.BundleMetadata; import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; import net.fabricmc.loom.util.Constants; public class MinecraftLibraryProvider { - public File MINECRAFT_LIBS; + private static final Pattern NATIVES_PATTERN = Pattern.compile("^(?.*)/(.*?)/(?.*)/((?.*?)-([0-9].*?)-)(?.*).jar$"); public void provide(MinecraftProviderImpl minecraftProvider, Project project) { MinecraftVersionMeta versionInfo = minecraftProvider.getVersionInfo(); + BundleMetadata serverBundleMetadata = minecraftProvider.getServerBundleMetadata(); - initFiles(project, minecraftProvider); + final boolean overrideLWJGL = LWJGLVersionOverride.overrideByDefault() || LWJGLVersionOverride.forceOverride(project) || Boolean.getBoolean("loom.test.lwjgloverride"); + + if (overrideLWJGL) { + project.getLogger().warn("Loom is upgrading Minecraft's LWJGL version to {}", LWJGLVersionOverride.LWJGL_VERSION); + } for (MinecraftVersionMeta.Library library : versionInfo.libraries()) { - if (library.isValidForOS() && !library.hasNatives() && library.artifact() != null) { - project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, project.getDependencies().module(library.name())); + if (overrideLWJGL && library.name().startsWith("org.lwjgl")) { + continue; } + + if (library.isValidForOS() && !library.hasNatives() && library.artifact() != null) { + if (serverBundleMetadata != null && isLibraryInBundle(serverBundleMetadata, library)) { + project.getDependencies().add(Constants.Configurations.MINECRAFT_SERVER_DEPENDENCIES, library.name()); + } else { + // Client only library, or legacy version + project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, library.name()); + } + } + + if (library.hasNativesForOS()) { + MinecraftVersionMeta.Download nativeDownload = library.classifierForOS(); + + Matcher matcher = NATIVES_PATTERN.matcher(nativeDownload.path()); + + if (!matcher.find()) { + project.getLogger().warn("Failed to match regex for natives path : " + nativeDownload.path()); + continue; + } + + final String group = matcher.group("group").replace("/", "."); + final String name = matcher.group("name"); + final String version = matcher.group("version"); + final String classifier = matcher.group("classifier"); + + final String dependencyNotation = "%s:%s:%s:%s".formatted(group, name, version, classifier); + + project.getLogger().debug("Add native dependency '{}'", dependencyNotation); + project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, dependencyNotation); + } + } + + if (overrideLWJGL) { + LWJGLVersionOverride.DEPENDENCIES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, s)); + LWJGLVersionOverride.NATIVES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, s)); + + // Add the native support mod that fixes a handful of issues related to the LWJGL update at runtime. + ExternalModuleDependency dependency = (ExternalModuleDependency) project.getDependencies().create(Constants.Dependencies.NATIVE_SUPPORT + Constants.Dependencies.Versions.NATIVE_SUPPORT_VERSION); + dependency.setTransitive(false); + project.getDependencies().add("modLocalRuntime", dependency); } } - private void initFiles(Project project, MinecraftProviderImpl minecraftProvider) { - LoomGradleExtension extension = LoomGradleExtension.get(project); - MINECRAFT_LIBS = new File(extension.getFiles().getUserCache(), "libraries"); + private static boolean isLibraryInBundle(BundleMetadata bundleMetadata, MinecraftVersionMeta.Library library) { + return bundleMetadata.libraries().stream().anyMatch(entry -> entry.name().equals(library.name())); } } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java index 264b855..0025e91 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java @@ -155,7 +155,7 @@ public class MinecraftMappedProvider extends DependencyProvider { // Remap the sig fixes from intermediary to the target namespace final Map remapped = new HashMap<>(); final TinyRemapper sigTinyRemapper = TinyRemapperHelper.getTinyRemapper(getProject(), MappingsNamespace.INTERMEDIARY.toString(), toM); - final Remapper sigAsmRemapper = sigTinyRemapper.getRemapper(); + final Remapper sigAsmRemapper = sigTinyRemapper.getEnvironment().getRemapper(); // Remap the class names and the signatures using a new tiny remapper instance. for (Map.Entry entry : mappingsProvider.getSignatureFixes().entrySet()) { diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftNativesProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftNativesProvider.java deleted file mode 100644 index 03904aa..0000000 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftNativesProvider.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2016-2021 FabricMC - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.fabricmc.loom.configuration.providers.minecraft; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -import org.apache.commons.io.FileUtils; -import org.gradle.api.GradleException; -import org.gradle.api.Project; - -import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.LoomGradlePlugin; -import net.fabricmc.loom.util.HashedDownloadUtil; -import net.fabricmc.loom.util.MirrorUtil; -import net.fabricmc.loom.util.ZipUtils; - -public class MinecraftNativesProvider { - private final Project project; - private final LoomGradleExtension extension; - private final File nativesDir; - private final File jarStore; - - public MinecraftNativesProvider(Project project) { - this.project = project; - extension = LoomGradleExtension.get(project); - - nativesDir = extension.getMinecraftProvider().nativesDir(); - jarStore = extension.getFiles().getNativesJarStore(); - } - - public static void provide(Project project) throws IOException { - new MinecraftNativesProvider(project).provide(); - } - - private void provide() throws IOException { - if (extension.getMinecraftProvider().hasCustomNatives()) { - if (!nativesDir.exists()) { - throw new RuntimeException("Could no find custom natives directory at " + nativesDir.getAbsolutePath()); - } - - return; - } - - if (!LoomGradlePlugin.refreshDeps && !requiresExtract()) { - project.getLogger().info("Natives do no need extracting, skipping"); - return; - } - - extractNatives(); - } - - private void extractNatives() throws IOException { - boolean offline = project.getGradle().getStartParameter().isOffline(); - - if (nativesDir.exists()) { - try { - FileUtils.deleteDirectory(nativesDir); - } catch (IOException e) { - throw new IOException("Failed to delete the natives directory, is the game running?", e); - } - } - - nativesDir.mkdirs(); - - for (MinecraftVersionMeta.Download library : getNatives()) { - File libJarFile = library.relativeFile(jarStore); - - if (!offline) { - HashedDownloadUtil.downloadIfInvalid(new URL(MirrorUtil.getLibrariesBase(project) + library.path()), libJarFile, library.sha1(), project.getLogger(), false); - } - - if (!libJarFile.exists()) { - throw new GradleException("Native jar not found at " + libJarFile.getAbsolutePath()); - } - - ZipUtils.unpackAll(libJarFile.toPath(), nativesDir.toPath()); - - // Store a file containing the hash of the extracted natives, used on subsequent runs to skip extracting all the natives if they haven't changed - File libSha1File = new File(nativesDir, libJarFile.getName() + ".sha1"); - FileUtils.writeStringToFile(libSha1File, library.sha1(), StandardCharsets.UTF_8); - } - } - - private boolean requiresExtract() { - List natives = getNatives(); - - if (natives.isEmpty()) { - throw new IllegalStateException("No natives found for the current system"); - } - - for (MinecraftVersionMeta.Download library : natives) { - File libJarFile = library.relativeFile(jarStore); - File libSha1File = new File(nativesDir, libJarFile.getName() + ".sha1"); - - if (!libSha1File.exists()) { - return true; - } - - try { - String sha1 = FileUtils.readFileToString(libSha1File, StandardCharsets.UTF_8); - - if (!sha1.equalsIgnoreCase(library.sha1())) { - return true; - } - } catch (IOException e) { - project.getLogger().error("Failed to read " + libSha1File.getAbsolutePath(), e); - return true; - } - } - - // All looks good, no need to re-extract - return false; - } - - private List getNatives() { - return extension.getMinecraftProvider().getVersionInfo().libraries().stream() - .filter((MinecraftVersionMeta.Library::hasNativesForOS)) - .map(MinecraftVersionMeta.Library::classifierForOS) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } -} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftVersionMeta.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftVersionMeta.java index 58a20db..86c1628 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftVersionMeta.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftVersionMeta.java @@ -81,7 +81,7 @@ public record MinecraftVersionMeta( return false; } - if (natives.get(OperatingSystem.getOS()) == null) { + if (natives.get(OperatingSystem.CURRENT_OS) == null) { return false; } @@ -89,7 +89,7 @@ public record MinecraftVersionMeta( } public Download classifierForOS() { - return downloads().classifier(natives.get(OperatingSystem.getOS())); + return downloads().classifier(natives.get(OperatingSystem.CURRENT_OS)); } public Download artifact() { @@ -119,7 +119,7 @@ public record MinecraftVersionMeta( public record OS(String name) { public boolean isValidForOS() { - return name() == null || name().equalsIgnoreCase(OperatingSystem.getOS()); + return name() == null || name().equalsIgnoreCase(OperatingSystem.CURRENT_OS); } } diff --git a/src/main/java/net/fabricmc/loom/extension/LoomFiles.java b/src/main/java/net/fabricmc/loom/extension/LoomFiles.java index 66307c1..4fc07be 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomFiles.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomFiles.java @@ -43,7 +43,7 @@ public interface LoomFiles { File getProjectPersistentCache(); File getProjectBuildCache(); File getRemappedModCache(); - File getNativesJarStore(); + File getNativesDirectory(Project project); File getDefaultLog4jConfigFile(); File getDevLauncherConfig(); File getUnpickLoggingConfigFile(); diff --git a/src/main/java/net/fabricmc/loom/extension/LoomFilesBaseImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomFilesBaseImpl.java index f99395e..a79bb56 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomFilesBaseImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomFilesBaseImpl.java @@ -26,6 +26,10 @@ package net.fabricmc.loom.extension; import java.io.File; +import org.gradle.api.Project; + +import net.fabricmc.loom.LoomGradleExtension; + public abstract class LoomFilesBaseImpl implements LoomFiles { protected abstract File getGradleUserHomeDir(); protected abstract File getRootDir(); @@ -70,8 +74,8 @@ public abstract class LoomFilesBaseImpl implements LoomFiles { } @Override - public File getNativesJarStore() { - return createFile(getUserCache(), "natives/jars"); + public File getNativesDirectory(Project project) { + return createFile(getRootProjectPersistentCache(), "natives/" + LoomGradleExtension.get(project).getMinecraftProvider().minecraftVersion()); } @Override diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java index da0fca7..5c98ac4 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java @@ -37,6 +37,7 @@ import java.util.function.Supplier; import org.cadixdev.lorenz.MappingSet; import org.cadixdev.mercury.Mercury; +import org.gradle.api.Action; import org.gradle.api.NamedDomainObjectProvider; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; @@ -145,8 +146,8 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen } @Override - public NamedDomainObjectProvider createLazyConfiguration(String name) { - NamedDomainObjectProvider provider = project.getConfigurations().register(name); + public NamedDomainObjectProvider createLazyConfiguration(String name, Action configurationAction) { + NamedDomainObjectProvider provider = project.getConfigurations().register(name, configurationAction); if (lazyConfigurations.containsKey(name)) { throw new IllegalStateException("Duplicate configuration name" + name); diff --git a/src/main/java/net/fabricmc/loom/extension/MixinExtensionApiImpl.java b/src/main/java/net/fabricmc/loom/extension/MixinExtensionApiImpl.java index cf958d9..58838e0 100644 --- a/src/main/java/net/fabricmc/loom/extension/MixinExtensionApiImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/MixinExtensionApiImpl.java @@ -29,7 +29,7 @@ import java.util.Objects; import org.gradle.api.Action; import org.gradle.api.InvalidUserDataException; import org.gradle.api.Project; -import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.SourceSet; @@ -110,8 +110,7 @@ public abstract class MixinExtensionApiImpl implements MixinExtensionAPI { private SourceSet resolveSourceSet(String sourceSetName) { // try to find sourceSet with name sourceSetName in this project - SourceSet sourceSet = project.getConvention().getPlugin(JavaPluginConvention.class) - .getSourceSets().findByName(sourceSetName); + SourceSet sourceSet = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets().findByName(sourceSetName); if (sourceSet == null) { throw new InvalidUserDataException("No sourceSet " + sourceSetName + " was found"); diff --git a/src/main/java/net/fabricmc/loom/extension/MixinExtensionImpl.java b/src/main/java/net/fabricmc/loom/extension/MixinExtensionImpl.java index 074251e..c8bf56a 100644 --- a/src/main/java/net/fabricmc/loom/extension/MixinExtensionImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/MixinExtensionImpl.java @@ -38,8 +38,8 @@ 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.plugins.BasePluginConvention; -import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.plugins.BasePluginExtension; +import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Input; @@ -67,7 +67,7 @@ public class MixinExtensionImpl extends MixinExtensionApiImpl implements MixinEx } private String getDefaultMixinRefmapName() { - String defaultRefmapName = project.getConvention().getPlugin(BasePluginConvention.class).getArchivesBaseName() + "-refmap.json"; + String defaultRefmapName = project.getExtensions().getByType(BasePluginExtension.class).getArchivesName().get() + "-refmap.json"; project.getLogger().info("Could not find refmap definition, will be using default name: " + defaultRefmapName); return defaultRefmapName; } @@ -87,7 +87,7 @@ public class MixinExtensionImpl extends MixinExtensionApiImpl implements MixinEx @Override @NotNull public Stream getMixinSourceSetsStream() { - return project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets().stream() + return project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets().stream() .filter(sourceSet -> MixinExtension.getMixinInformationContainer(sourceSet) != null); } @@ -122,7 +122,7 @@ public class MixinExtensionImpl extends MixinExtensionApiImpl implements MixinEx @Override public void init() { if (isDefault) { - project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets().forEach(this::add); + project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets().forEach(this::add); } isDefault = false; diff --git a/src/main/java/net/fabricmc/loom/task/AbstractRunTask.java b/src/main/java/net/fabricmc/loom/task/AbstractRunTask.java index 6bb63e5..baa5c93 100644 --- a/src/main/java/net/fabricmc/loom/task/AbstractRunTask.java +++ b/src/main/java/net/fabricmc/loom/task/AbstractRunTask.java @@ -46,6 +46,7 @@ public abstract class AbstractRunTask extends JavaExec { setClasspath(config.sourceSet.getRuntimeClasspath()); args(config.programArgs); + getMainClass().set(config.mainClass); } @Override @@ -64,11 +65,6 @@ public abstract class AbstractRunTask extends JavaExec { super.setWorkingDir(dir); } - @Override - public String getMain() { - return config.mainClass; - } - @Override public List getJvmArgs() { List superArgs = super.getJvmArgs(); diff --git a/src/main/java/net/fabricmc/loom/task/DownloadAssetsTask.java b/src/main/java/net/fabricmc/loom/task/DownloadAssetsTask.java index d862ea5..f03a107 100644 --- a/src/main/java/net/fabricmc/loom/task/DownloadAssetsTask.java +++ b/src/main/java/net/fabricmc/loom/task/DownloadAssetsTask.java @@ -30,7 +30,6 @@ import org.gradle.api.Project; import org.gradle.api.tasks.TaskAction; import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.configuration.providers.minecraft.MinecraftNativesProvider; import net.fabricmc.loom.configuration.providers.minecraft.assets.MinecraftAssetsProvider; public class DownloadAssetsTask extends AbstractLoomTask { @@ -40,6 +39,5 @@ public class DownloadAssetsTask extends AbstractLoomTask { LoomGradleExtension extension = getExtension(); MinecraftAssetsProvider.provide(extension.getMinecraftProvider(), project); - MinecraftNativesProvider.provide(project); } } diff --git a/src/main/java/net/fabricmc/loom/task/ExtractNativesTask.java b/src/main/java/net/fabricmc/loom/task/ExtractNativesTask.java new file mode 100644 index 0000000..0086ec4 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/task/ExtractNativesTask.java @@ -0,0 +1,50 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.task; + +import java.io.File; + +import javax.inject.Inject; + +import org.gradle.api.tasks.Sync; + +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.util.Constants; + +public abstract class ExtractNativesTask extends Sync { + @Inject + public ExtractNativesTask() { + // Is there a lazy way to do this for many files? - Doesnt seem there is... + for (File nativeFile : getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_NATIVES).getFiles()) { + from(getProject().zipTree(nativeFile), copySpec -> { + copySpec.exclude("META-INF/**"); + }); + } + + into(LoomGradleExtension.get(getProject()).getFiles().getNativesDirectory(getProject())); + + setDescription("Downloads and extracts the minecraft natives"); + } +} diff --git a/src/main/java/net/fabricmc/loom/task/LoomTasks.java b/src/main/java/net/fabricmc/loom/task/LoomTasks.java index 70c6a09..42732f8 100644 --- a/src/main/java/net/fabricmc/loom/task/LoomTasks.java +++ b/src/main/java/net/fabricmc/loom/task/LoomTasks.java @@ -43,6 +43,7 @@ public final class LoomTasks { public static void registerTasks(Project project) { TaskContainer tasks = project.getTasks(); + LoomGradleExtension extension = LoomGradleExtension.get(project); tasks.register("migrateMappings", MigrateMappingsTask.class, t -> { t.setDescription("Migrates mappings to a new version."); @@ -54,7 +55,11 @@ public final class LoomTasks { t.setGroup(Constants.TaskGroup.FABRIC); }); - tasks.register("downloadAssets", DownloadAssetsTask.class, t -> t.setDescription("Downloads required assets for Fabric.")); + TaskProvider extractNatives = tasks.register("extractNatives", ExtractNativesTask.class); + tasks.register("downloadAssets", DownloadAssetsTask.class, t -> { + t.dependsOn(extractNatives); + t.setDescription("Downloads required assets for Fabric."); + }); tasks.register("remapSourcesJar", RemapSourcesJarTask.class, t -> t.setDescription("Remaps the project sources jar to intermediary names.")); TaskProvider validateAccessWidener = tasks.register("validateAccessWidener", ValidateAccessWidenerTask.class, t -> { diff --git a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java index c976dde..053c93b 100644 --- a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java +++ b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java @@ -42,7 +42,7 @@ import org.gradle.api.IllegalDependencyNotation; import org.gradle.api.JavaVersion; import org.gradle.api.Project; import org.gradle.api.artifacts.Dependency; -import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.options.Option; @@ -171,12 +171,7 @@ public class MigrateMappingsTask extends AbstractLoomTask { project.getLogger().lifecycle(":remapping"); Mercury mercury = SourceRemapper.createMercuryWithClassPath(project, false); - final JavaPluginConvention convention = project.getConvention().findPlugin(JavaPluginConvention.class); - final JavaVersion javaVersion = convention != null - ? - convention.getSourceCompatibility() - : - JavaVersion.current(); + final JavaVersion javaVersion = project.getExtensions().getByType(JavaPluginExtension.class).getSourceCompatibility(); mercury.setSourceCompatibility(javaVersion.toString()); mercury.getClassPath().add(minecraftMappedProvider.getMappedJar().toPath()); diff --git a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java index 600d682..62dd881 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java @@ -124,7 +124,7 @@ public class RemapJarTask extends Jar { Project project = getProject(); LoomGradleExtension extension = LoomGradleExtension.get(getProject()); Path input = this.getInput().getAsFile().get().toPath(); - Path output = this.getArchivePath().toPath(); + Path output = this.getArchiveFile().get().getAsFile().toPath(); if (!Files.exists(input)) { throw new FileNotFoundException(input.toString()); diff --git a/src/main/java/net/fabricmc/loom/util/Architecture.java b/src/main/java/net/fabricmc/loom/util/Architecture.java new file mode 100644 index 0000000..3208a30 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/util/Architecture.java @@ -0,0 +1,47 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.util; + +public class Architecture { + public static final Architecture CURRENT = new Architecture(System.getProperty("os.arch")); + + private final String name; + + public Architecture(String name) { + this.name = name; + } + + public boolean is64Bit() { + return name.contains("64") || name.startsWith("armv8"); + } + + public boolean isArm() { + return name.startsWith("arm") || name.startsWith("aarch64"); + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/net/fabricmc/loom/util/ClosureAction.java b/src/main/java/net/fabricmc/loom/util/ClosureAction.java new file mode 100644 index 0000000..887f00f --- /dev/null +++ b/src/main/java/net/fabricmc/loom/util/ClosureAction.java @@ -0,0 +1,36 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.util; + +import groovy.lang.Closure; +import org.gradle.api.Action; + +public record ClosureAction(Closure closure) implements Action { + @Override + public void execute(T t) { + closure.setDelegate(t); + closure.call(t); + } +} diff --git a/src/main/java/net/fabricmc/loom/util/Constants.java b/src/main/java/net/fabricmc/loom/util/Constants.java index 44b1d40..5a06327 100644 --- a/src/main/java/net/fabricmc/loom/util/Constants.java +++ b/src/main/java/net/fabricmc/loom/util/Constants.java @@ -40,8 +40,6 @@ public class Constants { public static final String EXPERIMENTAL_VERSIONS = "https://maven.fabricmc.net/net/minecraft/experimental_versions.json"; public static final String FABRIC_REPOSITORY = "https://maven.fabricmc.net/"; - public static final String SYSTEM_ARCH = System.getProperty("os.arch").equals("64") ? "64" : "32"; - public static final int ASM_VERSION = Opcodes.ASM9; public static final List MOD_COMPILE_ENTRIES = ImmutableList.of( @@ -64,8 +62,13 @@ public class Constants { public static final String MOD_COMPILE_CLASSPATH_MAPPED = "modCompileClasspathMapped"; public static final String INCLUDE = "include"; public static final String MINECRAFT = "minecraft"; + /** + * The server specific configuration will be empty when using a legacy (pre 21w38a server jar) + * find the client only dependencies on the "minecraftLibraries" config. + */ + public static final String MINECRAFT_SERVER_DEPENDENCIES = "minecraftServerLibraries"; public static final String MINECRAFT_DEPENDENCIES = "minecraftLibraries"; - public static final String MINECRAFT_REMAP_CLASSPATH = "minecraftRemapClasspath"; + public static final String MINECRAFT_NATIVES = "minecraftNatives"; public static final String MINECRAFT_NAMED = "minecraftNamed"; public static final String MAPPINGS = "mappings"; public static final String MAPPINGS_FINAL = "mappingsFinal"; @@ -93,6 +96,7 @@ public class Constants { public static final String DEV_LAUNCH_INJECTOR = "net.fabricmc:dev-launch-injector:"; public static final String TERMINAL_CONSOLE_APPENDER = "net.minecrell:terminalconsoleappender:"; public static final String JETBRAINS_ANNOTATIONS = "org.jetbrains:annotations:"; + public static final String NATIVE_SUPPORT = "net.fabricmc:fabric-loom-native-support:"; private Dependencies() { } @@ -105,6 +109,7 @@ public class Constants { public static final String DEV_LAUNCH_INJECTOR = "0.2.1+build.8"; public static final String TERMINAL_CONSOLE_APPENDER = "1.2.0"; public static final String JETBRAINS_ANNOTATIONS = "23.0.0"; + public static final String NATIVE_SUPPORT_VERSION = "1.0.1"; private Versions() { } diff --git a/src/main/java/net/fabricmc/loom/util/FileSystemUtil.java b/src/main/java/net/fabricmc/loom/util/FileSystemUtil.java index 377bb8c..fb87072 100644 --- a/src/main/java/net/fabricmc/loom/util/FileSystemUtil.java +++ b/src/main/java/net/fabricmc/loom/util/FileSystemUtil.java @@ -28,9 +28,12 @@ import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; import java.nio.file.FileSystem; import java.nio.file.FileSystemAlreadyExistsException; import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.Collections; import java.util.Map; @@ -38,6 +41,20 @@ import java.util.function.Supplier; public final class FileSystemUtil { public record Delegate(FileSystem fs, boolean owner) implements AutoCloseable, Supplier { + public byte[] readAllBytes(String path) throws IOException { + Path fsPath = get().getPath(path); + + if (Files.exists(fsPath)) { + return Files.readAllBytes(fsPath); + } else { + throw new NoSuchFileException(fsPath.toString()); + } + } + + public String readString(String path) throws IOException { + return new String(readAllBytes(path), StandardCharsets.UTF_8); + } + @Override public void close() throws IOException { if (owner) { @@ -65,6 +82,10 @@ public final class FileSystemUtil { return getJarFileSystem(path.toUri(), create); } + public static Delegate getJarFileSystem(Path path) throws IOException { + return getJarFileSystem(path, false); + } + public static Delegate getJarFileSystem(URI uri, boolean create) throws IOException { URI jarUri; diff --git a/src/main/java/net/fabricmc/loom/util/ModUtils.java b/src/main/java/net/fabricmc/loom/util/ModUtils.java index 527bd7d..d49b518 100644 --- a/src/main/java/net/fabricmc/loom/util/ModUtils.java +++ b/src/main/java/net/fabricmc/loom/util/ModUtils.java @@ -25,18 +25,12 @@ 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; - } + return ZipUtils.contains(input.toPath(), "fabric.mod.json"); } } diff --git a/src/main/java/net/fabricmc/loom/util/OperatingSystem.java b/src/main/java/net/fabricmc/loom/util/OperatingSystem.java index 9df41ed..1e9bdc9 100644 --- a/src/main/java/net/fabricmc/loom/util/OperatingSystem.java +++ b/src/main/java/net/fabricmc/loom/util/OperatingSystem.java @@ -30,23 +30,21 @@ import java.net.StandardProtocolFamily; import java.nio.channels.ServerSocketChannel; public class OperatingSystem { - public static String getOS() { + public static final String WINDOWS = "windows"; + public static final String MAC_OS = "osx"; + public static final String LINUX = "linux"; + + public static final String CURRENT_OS = getOS(); + + private static String getOS() { String osName = System.getProperty("os.name").toLowerCase(); if (osName.contains("win")) { - return "windows"; + return WINDOWS; } else if (osName.contains("mac")) { - return "osx"; + return MAC_OS; } else { - return "linux"; - } - } - - public static String getArch() { - if (is64Bit()) { - return "64"; - } else { - return "32"; + return LINUX; } } @@ -54,10 +52,6 @@ public class OperatingSystem { return System.getProperty("sun.arch.data.model").contains("64"); } - public static boolean isWindows() { - return getOS().equals("windows"); - } - public static boolean isCIBuild() { String loomProperty = System.getProperty("fabric.loom.ci"); diff --git a/src/main/java/net/fabricmc/loom/util/ZipUtils.java b/src/main/java/net/fabricmc/loom/util/ZipUtils.java index 3416db3..2843a50 100644 --- a/src/main/java/net/fabricmc/loom/util/ZipUtils.java +++ b/src/main/java/net/fabricmc/loom/util/ZipUtils.java @@ -83,13 +83,7 @@ public class ZipUtils { public static byte[] unpack(Path zip, String path) throws IOException { try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(zip, false)) { - Path fsPath = fs.get().getPath(path); - - if (Files.exists(fsPath)) { - return Files.readAllBytes(fsPath); - } else { - throw new NoSuchFileException(fsPath.toString()); - } + return fs.readAllBytes(path); } } diff --git a/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy b/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy index aaca59c..ef596a7 100644 --- a/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy @@ -28,7 +28,7 @@ import org.gradle.util.GradleVersion class LoomTestConstants { public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion() - public final static String PRE_RELEASE_GRADLE = "7.4-20211203231050+0000" + public final static String PRE_RELEASE_GRADLE = "7.4-20211216231505+0000" public final static String[] STANDARD_TEST_VERSIONS = [DEFAULT_GRADLE, PRE_RELEASE_GRADLE] } diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/NativesTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/NativesTest.groovy new file mode 100644 index 0000000..76d5c43 --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/integration/NativesTest.groovy @@ -0,0 +1,86 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.test.integration + +import net.fabricmc.loom.test.util.GradleProjectTestTrait +import spock.lang.Specification +import spock.lang.Unroll +import spock.util.environment.RestoreSystemProperties + +import static net.fabricmc.loom.test.LoomTestConstants.STANDARD_TEST_VERSIONS +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS +import static org.gradle.testkit.runner.TaskOutcome.UP_TO_DATE + +class NativesTest extends Specification implements GradleProjectTestTrait { + @Unroll + def "Default natives for 1.18 (gradle #version)"() { + setup: + def gradle = gradleProject(project: "minimalBase", version: version) + + gradle.buildGradle << ''' + dependencies { + minecraft "com.mojang:minecraft:1.18" + mappings loom.officialMojangMappings() + } + ''' + + when: + // Run the task twice to ensure its up to date + def result = gradle.run(task: "extractNatives") + def result2 = gradle.run(task: "extractNatives") + + then: + result.task(":extractNatives").outcome == SUCCESS + result2.task(":extractNatives").outcome == UP_TO_DATE + + where: + version << STANDARD_TEST_VERSIONS + } + + @RestoreSystemProperties + @Unroll + def "Overridden natives for 1.18 (gradle #version)"() { + setup: + System.setProperty('loom.test.lwjgloverride', "true") + def gradle = gradleProject(project: "minimalBase", version: version) + + gradle.buildGradle << ''' + dependencies { + minecraft "com.mojang:minecraft:1.18" + mappings loom.officialMojangMappings() + } + ''' + + when: + // Run the task twice to ensure its up to date + def result = gradle.run(task: "extractNatives") + + then: + result.task(":extractNatives").outcome == SUCCESS + + where: + version << STANDARD_TEST_VERSIONS + } +} diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingSpecBuilderTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingSpecBuilderTest.groovy index 572545a..7164f4f 100644 --- a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingSpecBuilderTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingSpecBuilderTest.groovy @@ -30,29 +30,29 @@ import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuil import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpec import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMappingsSpec -import org.gradle.api.Action -import org.gradle.util.ConfigureUtil +import net.fabricmc.loom.util.ClosureAction import spock.lang.Specification class LayeredMappingSpecBuilderTest extends Specification { def "simple mojmap" () { when: - def spec = layered() { + def spec = layered { officialMojangMappings() } def layers = spec.layers() then: - spec.version == "layered+hash.2198" layers.size() == 2 + spec.version == "layered+hash.2198" layers[0].class == IntermediaryMappingsSpec layers[1].class == MojangMappingsSpec } def "simple mojmap with parchment" () { when: + def dep = "I like cake" def spec = layered() { officialMojangMappings() - parchment("I like cake") + parchment(dep) } def layers = spec.layers() def parchment = layers[2] as ParchmentMappingsSpec @@ -88,7 +88,7 @@ class LayeredMappingSpecBuilderTest extends Specification { def "simple mojmap with parchment keep prefix alternate hash" () { when: - def spec = layered() { + def spec = layered { officialMojangMappings() parchment("I really like cake") { it.removePrefix = false @@ -106,14 +106,9 @@ class LayeredMappingSpecBuilderTest extends Specification { parchment.removePrefix() == false } - // Gradle does this big of magic behind the scenes LayeredMappingSpec layered(@DelegatesTo(LayeredMappingSpecBuilderImpl) Closure cl) { - return layeredAction(ConfigureUtil.configureUsing(cl)) - } - - LayeredMappingSpec layeredAction(Action action) { LayeredMappingSpecBuilderImpl builder = new LayeredMappingSpecBuilderImpl() - action.execute(builder) + new ClosureAction(cl).execute(builder) return builder.build() } }