mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-03-27 19:57:00 -05:00
Merge 1.9
This commit is contained in:
@@ -3,9 +3,12 @@ package net.fabricmc.loom.bootstrap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.JavaVersion;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.configuration.BuildFeatures;
|
||||
import org.gradle.api.plugins.PluginAware;
|
||||
import org.gradle.util.GradleVersion;
|
||||
|
||||
@@ -13,20 +16,23 @@ import org.gradle.util.GradleVersion;
|
||||
* This bootstrap is compiled against a minimal gradle API and java 8, this allows us to show a nice error to users who run on unsupported configurations.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class LoomGradlePluginBootstrap implements Plugin<PluginAware> {
|
||||
private static final String MIN_SUPPORTED_GRADLE_VERSION = "8.10";
|
||||
public abstract class LoomGradlePluginBootstrap implements Plugin<PluginAware> {
|
||||
private static final String MIN_SUPPORTED_GRADLE_VERSION = "8.11";
|
||||
private static final int MIN_SUPPORTED_MAJOR_JAVA_VERSION = 17;
|
||||
private static final int MIN_SUPPORTED_MAJOR_IDEA_VERSION = 2022;
|
||||
|
||||
private static final String PLUGIN_CLASS_NAME = "net.fabricmc.loom.LoomGradlePlugin";
|
||||
private static final String IDEA_VERSION_PROP_KEY = "idea.version";
|
||||
|
||||
@Inject
|
||||
protected abstract BuildFeatures getBuildFeatures();
|
||||
|
||||
@Override
|
||||
public void apply(PluginAware pluginAware) {
|
||||
if (pluginAware instanceof Project) {
|
||||
Project project = (Project) pluginAware;
|
||||
|
||||
if (project.findProperty("fabric.loom.skip-env-validation") == null) {
|
||||
if (getBuildFeatures().getIsolatedProjects().getActive().get() || project.findProperty("fabric.loom.skip-env-validation") == null) {
|
||||
validateEnvironment();
|
||||
} else {
|
||||
project.getLogger().lifecycle("Loom environment validation disabled. Please re-enable before reporting any issues.");
|
||||
|
||||
30
build.gradle
30
build.gradle
@@ -7,37 +7,11 @@ plugins {
|
||||
id 'groovy'
|
||||
id 'checkstyle'
|
||||
id 'codenarc'
|
||||
alias(libs.plugins.kotlin) apply false // Delay this so we can perform magic 🪄 first.
|
||||
alias(libs.plugins.kotlin)
|
||||
alias(libs.plugins.spotless)
|
||||
alias(libs.plugins.retry)
|
||||
}
|
||||
|
||||
/**
|
||||
* Haha this is fun :) The Kotlin gradle plugin triggers deprecation warnings for custom configurations (https://youtrack.jetbrains.com/issue/KT-60879)
|
||||
* We need to make DefaultConfiguration.isSpecialCaseOfChangingUsage think that our configurstion is a special case and not deprecated.
|
||||
* We do this by setting DefaultConfiguration.roleAtCreation to LEGACY, thus isInLegacyRole will now return true.
|
||||
*
|
||||
* Yeah I know we can just ignore the deprecation warning, but doing so wouldn't alert us to issues when testing against pre-release Gradle versions. Also this is more fun :)
|
||||
*/
|
||||
def brokenConfigurations = [
|
||||
"commonDecompilerRuntimeClasspath",
|
||||
"fernflowerRuntimeClasspath",
|
||||
"cfrRuntimeClasspath",
|
||||
"vineflowerRuntimeClasspath"
|
||||
]
|
||||
|
||||
configurations.configureEach {
|
||||
if (brokenConfigurations.contains(it.name)) {
|
||||
// For some reason Gradle stops us from using Groovy magic to do this, so lets do it the boring way.
|
||||
def field = org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.class.getDeclaredField("roleAtCreation")
|
||||
field.setAccessible(true)
|
||||
field.set(it, ConfigurationRoles.LEGACY)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we apply the Kotlin plugin after, to allow for the above configuration to take place first
|
||||
apply plugin: libs.plugins.kotlin.get().pluginId
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
it.options.encoding = "UTF-8"
|
||||
}
|
||||
@@ -49,7 +23,7 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
|
||||
}
|
||||
|
||||
group = "dev.architectury"
|
||||
def baseVersion = '1.8'
|
||||
def baseVersion = '1.9'
|
||||
|
||||
def ENV = System.getenv()
|
||||
def runNumber = ENV.GITHUB_RUN_NUMBER ?: "9999"
|
||||
|
||||
@@ -3,3 +3,5 @@ description = A Gradle plugin for Fabric, Forge and Quilt modding.
|
||||
url = https://github.com/architectury/architectury-loom
|
||||
|
||||
kotlin.stdlib.default.dependency = false
|
||||
# Suppress a deprecation warning within the Kotlin Gradle plugin
|
||||
kotlin.mpp.keepMppDependenciesIntactInPoms = true
|
||||
@@ -1,5 +1,5 @@
|
||||
[versions]
|
||||
kotlin = "1.9.24"
|
||||
kotlin = "2.0.20"
|
||||
asm = "9.7.1"
|
||||
commons-io = "2.15.1"
|
||||
gson = "2.10.1"
|
||||
@@ -11,7 +11,6 @@ access-widener = "2.1.0"
|
||||
mapping-io = "0.6.1"
|
||||
lorenz-tiny = "4.0.2"
|
||||
mercury = "0.1.4.17"
|
||||
kotlinx-metadata = "0.9.0"
|
||||
loom-native = "0.2.0"
|
||||
|
||||
# Plugins
|
||||
@@ -52,7 +51,7 @@ fabric-loom-nativelib = { module = "net.fabricmc:fabric-loom-native", version.re
|
||||
|
||||
# Misc
|
||||
kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
kotlin-metadata = { module = "org.jetbrains.kotlinx:kotlinx-metadata-jvm", version.ref = "kotlinx-metadata" }
|
||||
kotlin-metadata = { module = "org.jetbrains.kotlin:kotlin-metadata-jvm", version.ref = "kotlin" }
|
||||
|
||||
# Forge support
|
||||
forge-installer-tools = { module = "net.minecraftforge:installertools", version.ref = "forge-installer-tools" }
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
[versions]
|
||||
spock = "2.3-groovy-3.0"
|
||||
junit = "5.11.1"
|
||||
junit = "5.11.3"
|
||||
javalin = "6.3.0"
|
||||
mockito = "5.13.0"
|
||||
mockito = "5.14.2"
|
||||
java-debug = "0.52.0"
|
||||
mixin = "0.15.3+mixin.0.8.7"
|
||||
|
||||
gradle-nightly = "8.12-20241009055624+0000"
|
||||
fabric-loader = "0.16.5"
|
||||
gradle-nightly = "8.12-20241110002642+0000"
|
||||
fabric-loader = "0.16.9"
|
||||
fabric-installer = "1.0.1"
|
||||
|
||||
[libraries]
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -153,6 +153,8 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI {
|
||||
|
||||
boolean isConfigurationCacheActive();
|
||||
|
||||
boolean isProjectIsolationActive();
|
||||
|
||||
// ===================
|
||||
// Architectury Loom
|
||||
// ===================
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -54,8 +55,11 @@ public class JarNester {
|
||||
|
||||
Preconditions.checkArgument(FabricModJsonFactory.isNestableModJar(modJar, platform), "Cannot nest jars into none mod jar " + modJar.getName());
|
||||
|
||||
// Ensure deterministic ordering of entries in fabric.mod.json
|
||||
Collection<File> sortedJars = jars.stream().sorted(Comparator.comparing(File::getName)).toList();
|
||||
|
||||
try {
|
||||
ZipUtils.add(modJar.toPath(), jars.stream().map(file -> {
|
||||
ZipUtils.add(modJar.toPath(), sortedJars.stream().map(file -> {
|
||||
try {
|
||||
return new Pair<>("META-INF/jars/" + file.getName(), Files.readAllBytes(file.toPath()));
|
||||
} catch (IOException e) {
|
||||
@@ -75,7 +79,7 @@ public class JarNester {
|
||||
nestedJars = new JsonArray();
|
||||
}
|
||||
|
||||
for (File file : jars) {
|
||||
for (File file : sortedJars) {
|
||||
String nestedJarPath = "META-INF/jars/" + file.getName();
|
||||
Preconditions.checkArgument(FabricModJsonFactory.isNestableModJar(file, platform), "Cannot nest none mod jar: " + file.getName());
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ package net.fabricmc.loom.configuration;
|
||||
|
||||
import static net.fabricmc.loom.util.Constants.Configurations;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -34,6 +35,7 @@ import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -49,6 +51,7 @@ import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.TaskContainer;
|
||||
import org.gradle.api.tasks.compile.JavaCompile;
|
||||
import org.gradle.api.tasks.javadoc.Javadoc;
|
||||
import org.gradle.api.tasks.testing.Test;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.InterfaceInjectionExtensionAPI;
|
||||
@@ -89,6 +92,7 @@ import net.fabricmc.loom.util.ExceptionUtil;
|
||||
import net.fabricmc.loom.util.ProcessUtil;
|
||||
import net.fabricmc.loom.util.gradle.GradleUtils;
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||
import net.fabricmc.loom.util.gradle.daemon.DaemonUtils;
|
||||
import net.fabricmc.loom.util.service.ScopedServiceFactory;
|
||||
import net.fabricmc.loom.util.service.ServiceFactory;
|
||||
|
||||
@@ -129,7 +133,7 @@ public abstract class CompileConfiguration implements Runnable {
|
||||
extension.setDependencyManager(dependencyManager);
|
||||
dependencyManager.handleDependencies(getProject(), serviceFactory);
|
||||
} catch (Exception e) {
|
||||
ExceptionUtil.processException(e, getProject());
|
||||
ExceptionUtil.processException(e, DaemonUtils.Context.fromProject(getProject()));
|
||||
disownLock();
|
||||
throw ExceptionUtil.createDescriptiveWrapper(RuntimeException::new, "Failed to setup Minecraft", e);
|
||||
}
|
||||
@@ -144,6 +148,7 @@ public abstract class CompileConfiguration implements Runnable {
|
||||
}
|
||||
|
||||
configureDecompileTasks(configContext);
|
||||
configureTestTask();
|
||||
|
||||
if (extension.isForgeLike()) {
|
||||
if (extension.isDataGenEnabled()) {
|
||||
@@ -335,6 +340,26 @@ public abstract class CompileConfiguration implements Runnable {
|
||||
.afterEvaluation();
|
||||
}
|
||||
|
||||
private void configureTestTask() {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
||||
|
||||
if (extension.getMods().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
getProject().getTasks().named(JavaPlugin.TEST_TASK_NAME, Test.class, test -> {
|
||||
String classPathGroups = extension.getMods().stream()
|
||||
.map(modSettings ->
|
||||
SourceSetHelper.getClasspath(modSettings, getProject()).stream()
|
||||
.map(File::getAbsolutePath)
|
||||
.collect(Collectors.joining(File.pathSeparator))
|
||||
)
|
||||
.collect(Collectors.joining(File.pathSeparator+File.pathSeparator));;
|
||||
|
||||
test.systemProperty("fabric.classPathGroups", classPathGroups);
|
||||
});
|
||||
}
|
||||
|
||||
private LockFile getLockFile() {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
||||
final Path cacheDirectory = extension.getFiles().getUserCache().toPath();
|
||||
|
||||
@@ -44,17 +44,16 @@ import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Delete;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.SourceSetContainer;
|
||||
import org.gradle.api.tasks.TaskContainer;
|
||||
import org.gradle.jvm.tasks.Jar;
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
import net.fabricmc.loom.util.download.DownloadException;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJson;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
|
||||
@@ -112,6 +111,7 @@ public abstract class FabricApiExtension {
|
||||
settings.getCreateSourceSet().convention(false);
|
||||
settings.getStrictValidation().convention(false);
|
||||
settings.getAddToResources().convention(true);
|
||||
settings.getClient().convention(false);
|
||||
|
||||
action.execute(settings);
|
||||
|
||||
@@ -133,33 +133,23 @@ public abstract class FabricApiExtension {
|
||||
jar.exclude(".cache/**");
|
||||
});
|
||||
|
||||
taskContainer.getByName(LifecycleBasePlugin.CLEAN_TASK_NAME, task -> {
|
||||
Delete clean = (Delete) task;
|
||||
clean.delete(outputDirectory);
|
||||
});
|
||||
|
||||
if (settings.getCreateSourceSet().get()) {
|
||||
final boolean isClientAndSplit = extension.areEnvironmentSourceSetsSplit() && settings.getClient().get();
|
||||
|
||||
SourceSetContainer sourceSets = SourceSetHelper.getSourceSets(getProject());
|
||||
|
||||
// Create the new datagen sourceset, depend on the main sourceset.
|
||||
// Create the new datagen sourceset, depend on the main or client sourceset.
|
||||
SourceSet dataGenSourceSet = sourceSets.create(DATAGEN_SOURCESET_NAME, sourceSet -> {
|
||||
sourceSet.setCompileClasspath(
|
||||
sourceSet.getCompileClasspath()
|
||||
.plus(mainSourceSet.getOutput())
|
||||
);
|
||||
dependsOn(sourceSet, mainSourceSet);
|
||||
|
||||
sourceSet.setRuntimeClasspath(
|
||||
sourceSet.getRuntimeClasspath()
|
||||
.plus(mainSourceSet.getOutput())
|
||||
);
|
||||
|
||||
extendsFrom(getProject(), sourceSet.getCompileClasspathConfigurationName(), mainSourceSet.getCompileClasspathConfigurationName());
|
||||
extendsFrom(getProject(), sourceSet.getRuntimeClasspathConfigurationName(), mainSourceSet.getRuntimeClasspathConfigurationName());
|
||||
if (isClientAndSplit) {
|
||||
dependsOn(sourceSet, SourceSetHelper.getSourceSetByName(MinecraftSourceSets.Split.CLIENT_ONLY_SOURCE_SET_NAME, getProject()));
|
||||
}
|
||||
});
|
||||
|
||||
settings.getModId().convention(getProject().provider(() -> {
|
||||
try {
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(dataGenSourceSet);
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(getProject(), dataGenSourceSet);
|
||||
|
||||
if (fabricModJson == null) {
|
||||
throw new RuntimeException("Could not find a fabric.mod.json file in the data source set or a value for DataGenerationSettings.getModId()");
|
||||
@@ -181,7 +171,7 @@ public abstract class FabricApiExtension {
|
||||
|
||||
if (settings.getCreateRunConfiguration().get()) {
|
||||
extension.getRunConfigs().create("datagen", run -> {
|
||||
run.inherit(extension.getRunConfigs().getByName("server"));
|
||||
run.inherit(extension.getRunConfigs().getByName(settings.getClient().get() ? "client" : "server"));
|
||||
run.setConfigName("Data Generation");
|
||||
|
||||
run.property("fabric-api.datagen");
|
||||
@@ -200,6 +190,11 @@ public abstract class FabricApiExtension {
|
||||
run.source(DATAGEN_SOURCESET_NAME);
|
||||
}
|
||||
});
|
||||
|
||||
// Add the output directory as an output allowing the task to be skipped.
|
||||
getProject().getTasks().named("runDatagen", task -> {
|
||||
task.getOutputs().dir(outputDirectory);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,6 +230,11 @@ public abstract class FabricApiExtension {
|
||||
* Contains a boolean property indicating whether the generated resources will be automatically added to the main sourceset.
|
||||
*/
|
||||
Property<Boolean> getAddToResources();
|
||||
|
||||
/**
|
||||
* Contains a boolean property indicating whether data generation will be compiled and ran with the client.
|
||||
*/
|
||||
Property<Boolean> getClient();
|
||||
}
|
||||
|
||||
private String getDependencyNotation(String moduleName, String fabricApiVersion) {
|
||||
@@ -326,4 +326,19 @@ public abstract class FabricApiExtension {
|
||||
configuration.extendsFrom(configurations.getByName(extendsFrom));
|
||||
});
|
||||
}
|
||||
|
||||
private void dependsOn(SourceSet sourceSet, SourceSet other) {
|
||||
sourceSet.setCompileClasspath(
|
||||
sourceSet.getCompileClasspath()
|
||||
.plus(other.getOutput())
|
||||
);
|
||||
|
||||
sourceSet.setRuntimeClasspath(
|
||||
sourceSet.getRuntimeClasspath()
|
||||
.plus(other.getOutput())
|
||||
);
|
||||
|
||||
extendsFrom(getProject(), sourceSet.getCompileClasspathConfigurationName(), other.getCompileClasspathConfigurationName());
|
||||
extendsFrom(getProject(), sourceSet.getRuntimeClasspathConfigurationName(), other.getRuntimeClasspathConfigurationName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,8 @@ public record SpecContextImpl(List<FabricModJson> modDependencies, List<FabricMo
|
||||
}
|
||||
}
|
||||
|
||||
if (!GradleUtils.getBooleanProperty(project, Constants.Properties.DISABLE_PROJECT_DEPENDENT_MODS)) {
|
||||
// TODO provide a project isolated way of doing this.
|
||||
if (!extension.isProjectIsolationActive() && !GradleUtils.getBooleanProperty(project, Constants.Properties.DISABLE_PROJECT_DEPENDENT_MODS)) {
|
||||
// Add all the dependent projects
|
||||
for (Project dependentProject : getDependentProjects(project).toList()) {
|
||||
mods.addAll(fmjCache.computeIfAbsent(dependentProject.getPath(), $ -> {
|
||||
@@ -97,8 +98,8 @@ public record SpecContextImpl(List<FabricModJson> modDependencies, List<FabricMo
|
||||
}
|
||||
|
||||
private static Stream<Project> getDependentProjects(Project project) {
|
||||
final Stream<Project> runtimeProjects = getLoomProjectDependencies(project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME));
|
||||
final Stream<Project> compileProjects = getLoomProjectDependencies(project.getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME));
|
||||
final Stream<Project> runtimeProjects = getLoomProjectDependencies(project, project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME));
|
||||
final Stream<Project> compileProjects = getLoomProjectDependencies(project, project.getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME));
|
||||
|
||||
return Stream.concat(runtimeProjects, compileProjects)
|
||||
.distinct();
|
||||
@@ -154,19 +155,19 @@ public record SpecContextImpl(List<FabricModJson> modDependencies, List<FabricMo
|
||||
|
||||
// Returns a list of Loom Projects found in both the runtime and compile classpath
|
||||
private static Stream<Project> getCompileRuntimeProjectDependencies(Project project) {
|
||||
final Stream<Project> runtimeProjects = getLoomProjectDependencies(project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME));
|
||||
final List<Project> compileProjects = getLoomProjectDependencies(project.getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME)).toList();
|
||||
final Stream<Project> runtimeProjects = getLoomProjectDependencies(project, project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME));
|
||||
final List<Project> compileProjects = getLoomProjectDependencies(project, project.getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME)).toList();
|
||||
|
||||
return runtimeProjects
|
||||
.filter(compileProjects::contains); // Use the intersection of the two configurations.
|
||||
}
|
||||
|
||||
// Returns a list of Loom Projects found in the provided Configuration
|
||||
private static Stream<Project> getLoomProjectDependencies(Configuration configuration) {
|
||||
private static Stream<Project> getLoomProjectDependencies(Project project, Configuration configuration) {
|
||||
return configuration.getAllDependencies()
|
||||
.withType(ProjectDependency.class)
|
||||
.stream()
|
||||
.map(GradleUtils::getDependencyProject)
|
||||
.map((d) -> project.project(d.getPath()))
|
||||
.filter(GradleUtils::isLoomProject);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ import net.fabricmc.loom.configuration.providers.minecraft.library.MinecraftLibr
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.library.processors.RuntimeLog4jLibraryProcessor;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.Platform;
|
||||
import net.fabricmc.loom.util.gradle.GradleUtils;
|
||||
|
||||
public class MinecraftLibraryProvider {
|
||||
private static final Platform platform = Platform.CURRENT;
|
||||
@@ -124,7 +125,7 @@ public class MinecraftLibraryProvider {
|
||||
}
|
||||
|
||||
private JavaVersion getTargetRuntimeJavaVersion() {
|
||||
final Object property = project.findProperty(Constants.Properties.RUNTIME_JAVA_COMPATIBILITY_VERSION);
|
||||
final Object property = GradleUtils.getProperty(project, Constants.Properties.RUNTIME_JAVA_COMPATIBILITY_VERSION);
|
||||
|
||||
if (property != null) {
|
||||
// This is very much a last ditch effort to allow users to set the runtime java version
|
||||
|
||||
@@ -59,6 +59,13 @@ public abstract class SandboxConfiguration implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
||||
|
||||
if (extension.isProjectIsolationActive()) {
|
||||
LOGGER.debug("Skipping sandbox configuration as project isolation is enabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (getProject().findProperty(Constants.Properties.SANDBOX) == null) {
|
||||
LOGGER.debug("No fabric sandbox property set");
|
||||
return;
|
||||
|
||||
@@ -342,7 +342,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
@Override
|
||||
public String getModVersion() {
|
||||
try {
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(SourceSetHelper.getMainSourceSet(getProject()));
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(getProject(), SourceSetHelper.getMainSourceSet(getProject()));
|
||||
|
||||
if (fabricModJson == null) {
|
||||
throw new RuntimeException("Could not find a fabric.mod.json file in the main sourceset");
|
||||
|
||||
@@ -131,6 +131,10 @@ public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl
|
||||
if (refreshDeps) {
|
||||
project.getLogger().lifecycle("Refresh dependencies is in use, loom will be significantly slower.");
|
||||
}
|
||||
|
||||
if (isolatedProjectsActive) {
|
||||
project.getLogger().lifecycle("Isolated projects is enabled, Loom support is highly experimental, not all features will be enabled.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -339,6 +343,11 @@ public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl
|
||||
return configurationCacheActive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProjectIsolationActive() {
|
||||
return isolatedProjectsActive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForgeExtensionAPI getForge() {
|
||||
ModPlatform.assertPlatform(this, ModPlatform.FORGE);
|
||||
|
||||
@@ -126,6 +126,11 @@ public abstract class AbstractRemapJarTask extends Jar {
|
||||
usesService(jarManifestServiceProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void copy() {
|
||||
// Skip the default copy behaviour of AbstractCopyTask.
|
||||
}
|
||||
|
||||
public final <P extends AbstractRemapParams> void submitWork(Class<? extends AbstractRemapAction<P>> workAction, Action<P> action) {
|
||||
final WorkQueue workQueue = getWorkerExecutor().noIsolation();
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
@@ -43,7 +44,6 @@ import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.provider.MapProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.services.ServiceReference;
|
||||
import org.gradle.api.specs.Spec;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
@@ -52,9 +52,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfig;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.gradle.SyncTaskBuildService;
|
||||
|
||||
public abstract class AbstractRunTask extends JavaExec {
|
||||
private static final CharsetEncoder ASCII_ENCODER = StandardCharsets.US_ASCII.newEncoder();
|
||||
@@ -70,15 +70,14 @@ public abstract class AbstractRunTask extends JavaExec {
|
||||
protected abstract Property<Boolean> getUseArgFile();
|
||||
@Input
|
||||
protected abstract Property<String> getProjectDir();
|
||||
@Input
|
||||
// We use a string here, as it's technically an output, but we don't want to cache runs of this task by default.
|
||||
protected abstract Property<String> getArgFilePath();
|
||||
|
||||
// We control the classpath, as we use a ArgFile to pass it over the command line: https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html#commandlineargfile
|
||||
@InputFiles
|
||||
protected abstract ConfigurableFileCollection getInternalClasspath();
|
||||
|
||||
// Prevent Gradle from running two run tasks in parallel
|
||||
@ServiceReference(SyncTaskBuildService.NAME)
|
||||
abstract Property<SyncTaskBuildService> getSyncTask();
|
||||
|
||||
public AbstractRunTask(Function<Project, RunConfig> configProvider) {
|
||||
super();
|
||||
setGroup(Constants.TaskGroup.FABRIC);
|
||||
@@ -100,6 +99,10 @@ public abstract class AbstractRunTask extends JavaExec {
|
||||
getInternalJvmArgs().set(config.map(runConfig -> runConfig.vmArgs));
|
||||
getUseArgFile().set(getProject().provider(this::canUseArgFile));
|
||||
getProjectDir().set(getProject().getProjectDir().getAbsolutePath());
|
||||
|
||||
File buildCache = LoomGradleExtension.get(getProject()).getFiles().getProjectBuildCache();
|
||||
File argFile = new File(buildCache, "argFiles/" + getName());
|
||||
getArgFilePath().set(argFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
private boolean canUseArgFile() {
|
||||
@@ -154,7 +157,8 @@ public abstract class AbstractRunTask extends JavaExec {
|
||||
.collect(Collectors.joining(File.pathSeparator));
|
||||
|
||||
try {
|
||||
final Path argsFile = Files.createTempFile("loom-classpath", ".args");
|
||||
final Path argsFile = Paths.get(getArgFilePath().get());
|
||||
Files.createDirectories(argsFile.getParent());
|
||||
Files.writeString(argsFile, content, StandardCharsets.UTF_8);
|
||||
args.add("@" + argsFile.toAbsolutePath());
|
||||
} catch (IOException e) {
|
||||
|
||||
@@ -97,10 +97,12 @@ import net.fabricmc.loom.util.ExceptionUtil;
|
||||
import net.fabricmc.loom.util.FileSystemUtil;
|
||||
import net.fabricmc.loom.util.IOStringConsumer;
|
||||
import net.fabricmc.loom.util.Platform;
|
||||
import net.fabricmc.loom.util.gradle.GradleUtils;
|
||||
import net.fabricmc.loom.util.gradle.SyncTaskBuildService;
|
||||
import net.fabricmc.loom.util.gradle.ThreadedProgressLoggerConsumer;
|
||||
import net.fabricmc.loom.util.gradle.ThreadedSimpleProgressLogger;
|
||||
import net.fabricmc.loom.util.gradle.WorkerDaemonClientsManagerHelper;
|
||||
import net.fabricmc.loom.util.gradle.daemon.DaemonUtils;
|
||||
import net.fabricmc.loom.util.ipc.IPCClient;
|
||||
import net.fabricmc.loom.util.ipc.IPCServer;
|
||||
import net.fabricmc.loom.util.service.ScopedServiceFactory;
|
||||
@@ -178,6 +180,14 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
@Internal
|
||||
protected abstract RegularFileProperty getDecompileCacheFile();
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Input
|
||||
protected abstract Property<Integer> getMaxCachedFiles();
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Input
|
||||
protected abstract Property<Integer> getMaxCacheFileAge();
|
||||
|
||||
// Injects
|
||||
@Inject
|
||||
protected abstract WorkerExecutor getWorkerExecutor();
|
||||
@@ -191,6 +201,9 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
@Inject
|
||||
protected abstract ProgressLoggerFactory getProgressLoggerFactory();
|
||||
|
||||
@Nested
|
||||
protected abstract Property<DaemonUtils.Context> getDaemonUtilsContext();
|
||||
|
||||
// Prevent Gradle from running two gen sources tasks in parallel
|
||||
@ServiceReference(SyncTaskBuildService.NAME)
|
||||
abstract Property<SyncTaskBuildService> getSyncTask();
|
||||
@@ -242,6 +255,11 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
|
||||
getMappings().set(SourceMappingsService.create(getProject()));
|
||||
|
||||
getMaxCachedFiles().set(GradleUtils.getIntegerPropertyProvider(getProject(), Constants.Properties.DECOMPILE_CACHE_MAX_FILES).orElse(50_000));
|
||||
getMaxCacheFileAge().set(GradleUtils.getIntegerPropertyProvider(getProject(), Constants.Properties.DECOMPILE_CACHE_MAX_AGE).orElse(90));
|
||||
|
||||
getDaemonUtilsContext().set(getProject().getObjects().newInstance(DaemonUtils.Context.class, getProject()));
|
||||
|
||||
mustRunAfter(getProject().getTasks().withType(AbstractRemapJarTask.class));
|
||||
}
|
||||
|
||||
@@ -259,7 +277,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
try (var timer = new Timer("Decompiled sources")) {
|
||||
runWithoutCache();
|
||||
} catch (Exception e) {
|
||||
ExceptionUtil.processException(e, getProject());
|
||||
ExceptionUtil.processException(e, getDaemonUtilsContext().get());
|
||||
throw ExceptionUtil.createDescriptiveWrapper(RuntimeException::new, "Failed to decompile", e);
|
||||
}
|
||||
|
||||
@@ -277,14 +295,22 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
}
|
||||
|
||||
// TODO ensure we have a lock on this file to prevent multiple tasks from running at the same time
|
||||
// TODO handle being unable to read the cache file
|
||||
Files.createDirectories(cacheFile.getParent());
|
||||
|
||||
if (Files.exists(cacheFile)) {
|
||||
try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(cacheFile, true)) {
|
||||
// Success, cache exists and can be read
|
||||
} catch (IOException e) {
|
||||
getLogger().warn("Discarding invalid decompile cache file: {}", cacheFile, e);
|
||||
Files.delete(cacheFile);
|
||||
}
|
||||
}
|
||||
|
||||
try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(cacheFile, true)) {
|
||||
runWithCache(fs.getRoot());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ExceptionUtil.processException(e, getProject());
|
||||
ExceptionUtil.processException(e, getDaemonUtilsContext().get());
|
||||
throw ExceptionUtil.createDescriptiveWrapper(RuntimeException::new, "Failed to decompile", e);
|
||||
}
|
||||
}
|
||||
@@ -293,13 +319,14 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
final Path classesInputJar = getClassesInputJar().getSingleFile().toPath();
|
||||
final Path sourcesOutputJar = getSourcesOutputJar().get().getAsFile().toPath();
|
||||
final Path classesOutputJar = getClassesOutputJar().getSingleFile().toPath();
|
||||
final var cacheRules = new CachedFileStoreImpl.CacheRules(50_000, Duration.ofDays(90));
|
||||
final var cacheRules = new CachedFileStoreImpl.CacheRules(getMaxCachedFiles().get(), Duration.ofDays(getMaxCacheFileAge().get()));
|
||||
final var decompileCache = new CachedFileStoreImpl<>(cacheRoot, CachedData.SERIALIZER, cacheRules);
|
||||
final String cacheKey = getCacheKey();
|
||||
final CachedJarProcessor cachedJarProcessor = new CachedJarProcessor(decompileCache, cacheKey);
|
||||
final CachedJarProcessor.WorkRequest workRequest;
|
||||
|
||||
getLogger().info("Decompile cache key: {}", cacheKey);
|
||||
getLogger().debug("Decompile cache rules: {}", cacheRules);
|
||||
|
||||
try (var timer = new Timer("Prepare job")) {
|
||||
workRequest = cachedJarProcessor.prepareJob(classesInputJar);
|
||||
|
||||
@@ -142,7 +142,8 @@ public abstract class RemapTaskConfiguration implements Runnable {
|
||||
final Jar jarTask = (Jar) getTasks().getByName(JavaPlugin.JAR_TASK_NAME);
|
||||
configuration.getArtifacts().removeIf(artifact -> {
|
||||
// if the artifact is built by the jar task, and has the same output path.
|
||||
return artifact.getFile().getAbsolutePath().equals(jarTask.getArchiveFile().get().getAsFile().getAbsolutePath()) && artifact.getBuildDependencies().getDependencies(null).contains(jarTask);
|
||||
return artifact.getFile().getAbsolutePath().equals(jarTask.getArchiveFile().get().getAsFile().getAbsolutePath())
|
||||
&& (extension.isProjectIsolationActive() || artifact.getBuildDependencies().getDependencies(null).contains(jarTask));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -59,8 +59,6 @@ import net.fabricmc.tinyremapper.IMappingProvider;
|
||||
public class MixinAPMappingService extends Service<MixinAPMappingService.Options> {
|
||||
public static final ServiceType<Options, MixinAPMappingService> TYPE = new ServiceType<>(Options.class, MixinAPMappingService.class);
|
||||
|
||||
// TODO look into seeing if we can make this an option, it likely breaks project isolation.
|
||||
private static final boolean INCLUDE_CROSS_PROJECT_MAPPINGS = true;
|
||||
// Again look into what the result of changing this would be.
|
||||
private static final boolean USE_ALL_SOURCE_SETS = true;
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MixinAPMappingService.class);
|
||||
@@ -105,7 +103,8 @@ public class MixinAPMappingService extends Service<MixinAPMappingService.Options
|
||||
}
|
||||
};
|
||||
|
||||
if (!INCLUDE_CROSS_PROJECT_MAPPINGS) {
|
||||
if (thisExtension.isProjectIsolationActive()) {
|
||||
// TODO provide a project isolated way of remapping with dependency mixin mapping
|
||||
processProject.accept(thisProject);
|
||||
} else {
|
||||
GradleUtils.allLoomProjects(thisProject.getGradle(), project -> {
|
||||
|
||||
@@ -111,7 +111,7 @@ public class TinyRemapperService extends Service<TinyRemapperService.Options> im
|
||||
options.getUselegacyMixinAP().set(legacyMixin);
|
||||
options.getKotlinClasspathService().set(KotlinClasspathService.createOptions(project));
|
||||
options.getClasspath().from(classpath);
|
||||
options.getKnownIndyBsms().set(extension.getKnownIndyBsms());
|
||||
options.getKnownIndyBsms().set(extension.getKnownIndyBsms().get().stream().sorted().toList());
|
||||
options.getRemapperExtensions().set(extension.getRemapperExtensions());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -166,6 +166,8 @@ public class Constants {
|
||||
* Only set this when you have a good reason to do so, the default should be fine for almost all cases.
|
||||
*/
|
||||
public static final String RUNTIME_JAVA_COMPATIBILITY_VERSION = "fabric.loom.runtimeJavaCompatibilityVersion";
|
||||
public static final String DECOMPILE_CACHE_MAX_FILES = "fabric.loom.decompileCacheMaxFiles";
|
||||
public static final String DECOMPILE_CACHE_MAX_AGE = "fabric.loom.decompileCacheMaxAge";
|
||||
public static final String ALLOW_MISMATCHED_PLATFORM_VERSION = "loom.allowMismatchedPlatformVersion";
|
||||
public static final String IGNORE_DEPENDENCY_LOOM_VERSION_VALIDATION = "loom.ignoreDependencyLoomVersionValidation";
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -60,7 +59,7 @@ public final class ExceptionUtil {
|
||||
return constructor.apply(descriptiveMessage, cause);
|
||||
}
|
||||
|
||||
public static void processException(Throwable e, Project project) {
|
||||
public static void processException(Throwable e, DaemonUtils.Context context) {
|
||||
Throwable cause = e;
|
||||
boolean unrecoverable = false;
|
||||
|
||||
@@ -68,7 +67,7 @@ public final class ExceptionUtil {
|
||||
if (cause instanceof FileSystemUtil.UnrecoverableZipException) {
|
||||
unrecoverable = true;
|
||||
} else if (cause instanceof FileSystemException fse) {
|
||||
printFileLocks(fse.getFile(), project);
|
||||
printFileLocks(fse.getFile());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -76,11 +75,11 @@ public final class ExceptionUtil {
|
||||
}
|
||||
|
||||
if (unrecoverable) {
|
||||
DaemonUtils.tryStopGradleDaemon(project);
|
||||
DaemonUtils.tryStopGradleDaemon(context);
|
||||
}
|
||||
}
|
||||
|
||||
private static void printFileLocks(String filename, Project project) {
|
||||
private static void printFileLocks(String filename) {
|
||||
final Path path = Paths.get(filename);
|
||||
|
||||
if (!Files.exists(path)) {
|
||||
@@ -100,13 +99,13 @@ public final class ExceptionUtil {
|
||||
return;
|
||||
}
|
||||
|
||||
final ProcessUtil processUtil = ProcessUtil.create(project);
|
||||
final ProcessUtil processUtil = ProcessUtil.create(LOGGER.isInfoEnabled() ? ProcessUtil.ArgumentVisibility.SHOW_SENSITIVE : ProcessUtil.ArgumentVisibility.HIDE);
|
||||
|
||||
final String noun = processes.size() == 1 ? "process has" : "processes have";
|
||||
project.getLogger().error("The following {} a lock on the file '{}':", noun, path);
|
||||
LOGGER.error("The following {} a lock on the file '{}':", noun, path);
|
||||
|
||||
for (ProcessHandle process : processes) {
|
||||
project.getLogger().error(processUtil.printWithParents(process));
|
||||
LOGGER.error(processUtil.printWithParents(process));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import java.util.List;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.Gson;
|
||||
import kotlinx.metadata.jvm.KotlinClassMetadata;
|
||||
import kotlin.metadata.jvm.KotlinClassMetadata;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.commons.ClassRemapper;
|
||||
|
||||
@@ -37,18 +37,22 @@ import org.slf4j.LoggerFactory;
|
||||
import net.fabricmc.loom.nativeplatform.LoomNativePlatform;
|
||||
import net.fabricmc.loom.nativeplatform.LoomNativePlatformException;
|
||||
|
||||
public record ProcessUtil(LogLevel logLevel) {
|
||||
public record ProcessUtil(ArgumentVisibility argumentVisibility) {
|
||||
private static final String EXPLORER_COMMAND = "C:\\Windows\\explorer.exe";
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ProcessUtil.class);
|
||||
|
||||
public static ProcessUtil create(Project project) {
|
||||
return new ProcessUtil(project.getGradle().getStartParameter().getLogLevel());
|
||||
return create(ArgumentVisibility.get(project));
|
||||
}
|
||||
|
||||
public static ProcessUtil create(ArgumentVisibility argumentVisibility) {
|
||||
return new ProcessUtil(argumentVisibility);
|
||||
}
|
||||
|
||||
public String printWithParents(ProcessHandle handle) {
|
||||
String result = printWithParents(handle, 0).trim();
|
||||
|
||||
if (logLevel != LogLevel.INFO && logLevel != LogLevel.DEBUG) {
|
||||
if (argumentVisibility == ArgumentVisibility.HIDE) {
|
||||
return "Run with --info or --debug to show arguments, may reveal sensitive info\n" + result;
|
||||
}
|
||||
|
||||
@@ -75,7 +79,7 @@ public record ProcessUtil(LogLevel logLevel) {
|
||||
}
|
||||
|
||||
private Optional<String> getProcessArguments(ProcessHandle handle) {
|
||||
if (logLevel != LogLevel.INFO && logLevel != LogLevel.DEBUG) {
|
||||
if (argumentVisibility != ArgumentVisibility.SHOW_SENSITIVE) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -117,4 +121,14 @@ public record ProcessUtil(LogLevel logLevel) {
|
||||
|
||||
return Optional.of(joiner.toString());
|
||||
}
|
||||
|
||||
public enum ArgumentVisibility {
|
||||
HIDE,
|
||||
SHOW_SENSITIVE;
|
||||
|
||||
static ArgumentVisibility get(Project project) {
|
||||
final LogLevel logLevel = project.getGradle().getStartParameter().getLogLevel();
|
||||
return (logLevel == LogLevel.INFO || logLevel == LogLevel.DEBUG) ? SHOW_SENSITIVE : HIDE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import dev.architectury.loom.metadata.ModMetadataFile;
|
||||
import dev.architectury.loom.metadata.ModMetadataFiles;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
@@ -134,8 +135,8 @@ public final class FabricModJsonFactory {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static FabricModJson createFromSourceSetsNullable(SourceSet... sourceSets) throws IOException {
|
||||
final File file = SourceSetHelper.findFirstFileInResource(FABRIC_MOD_JSON, sourceSets);
|
||||
public static FabricModJson createFromSourceSetsNullable(Project project, SourceSet... sourceSets) throws IOException {
|
||||
final File file = SourceSetHelper.findFirstFileInResource(FABRIC_MOD_JSON, project, sourceSets);
|
||||
|
||||
if (file == null) {
|
||||
// Try another mod metadata file if fabric.mod.json wasn't found.
|
||||
@@ -149,7 +150,7 @@ public final class FabricModJsonFactory {
|
||||
}
|
||||
|
||||
try (Reader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
|
||||
return create(LoomGradlePlugin.GSON.fromJson(reader, JsonObject.class), new FabricModJsonSource.SourceSetSource(sourceSets));
|
||||
return create(LoomGradlePlugin.GSON.fromJson(reader, JsonObject.class), new FabricModJsonSource.SourceSetSource(project, sourceSets));
|
||||
} catch (JsonSyntaxException e) {
|
||||
LOGGER.warn("Failed to parse fabric.mod.json: {}", file.getAbsolutePath());
|
||||
return null;
|
||||
|
||||
@@ -48,7 +48,7 @@ public class FabricModJsonHelpers {
|
||||
}
|
||||
|
||||
try {
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(sourceSets.toArray(SourceSet[]::new));
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(project, sourceSets.toArray(SourceSet[]::new));
|
||||
|
||||
if (fabricModJson != null) {
|
||||
return List.of(fabricModJson);
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
@@ -56,14 +57,14 @@ public interface FabricModJsonSource {
|
||||
}
|
||||
}
|
||||
|
||||
record SourceSetSource(SourceSet... sourceSets) implements FabricModJsonSource {
|
||||
record SourceSetSource(Project project, SourceSet... sourceSets) implements FabricModJsonSource {
|
||||
@Override
|
||||
public byte[] read(String path) throws IOException {
|
||||
return Files.readAllBytes(findFile(path).toPath());
|
||||
}
|
||||
|
||||
private File findFile(String path) throws IOException {
|
||||
final File file = SourceSetHelper.findFirstFileInResource(path, sourceSets);
|
||||
final File file = SourceSetHelper.findFirstFileInResource(path, project, sourceSets);
|
||||
|
||||
if (file == null) {
|
||||
throw new FileNotFoundException("Could not find: " + path);
|
||||
|
||||
@@ -25,24 +25,18 @@
|
||||
package net.fabricmc.loom.util.gradle;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.ProjectDependency;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.internal.artifacts.dependencies.DefaultProjectDependency;
|
||||
import org.gradle.api.internal.catalog.DelegatingProjectDependency;
|
||||
import org.gradle.api.invocation.Gradle;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public final class GradleUtils {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(GradleUtils.class);
|
||||
|
||||
private GradleUtils() {
|
||||
}
|
||||
|
||||
@@ -71,6 +65,13 @@ public final class GradleUtils {
|
||||
}
|
||||
|
||||
public static Provider<Boolean> getBooleanPropertyProvider(Project project, String key) {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
|
||||
if (extension.isProjectIsolationActive()) {
|
||||
// TODO write a custom property parser for isolated projects
|
||||
return project.provider(() -> false);
|
||||
}
|
||||
|
||||
// Works around https://github.com/gradle/gradle/issues/23572
|
||||
return project.provider(() -> {
|
||||
final Object value = project.findProperty(key);
|
||||
@@ -87,10 +88,37 @@ public final class GradleUtils {
|
||||
});
|
||||
}
|
||||
|
||||
public static Provider<Integer> getIntegerPropertyProvider(Project project, String key) {
|
||||
return project.provider(() -> {
|
||||
final Object value = project.findProperty(key);
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return Integer.parseInt(value.toString());
|
||||
} catch (final NumberFormatException ex) {
|
||||
throw new IllegalArgumentException("Property " + key + " must be an integer", ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean getBooleanProperty(Project project, String key) {
|
||||
return getBooleanPropertyProvider(project, key).getOrElse(false);
|
||||
}
|
||||
|
||||
public static Object getProperty(Project project, String key) {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
|
||||
if (extension.isProjectIsolationActive()) {
|
||||
// TODO write a custom property parser for isolated projects
|
||||
return null;
|
||||
}
|
||||
|
||||
return project.findProperty(key);
|
||||
}
|
||||
|
||||
// A hack to include the given file in the configuration cache input
|
||||
// this ensures that configuration cache is invalidated when the file changes
|
||||
public static File configurationInputFile(Project project, File file) {
|
||||
@@ -98,33 +126,4 @@ public final class GradleUtils {
|
||||
property.set(file);
|
||||
return property.getAsFile().get();
|
||||
}
|
||||
|
||||
// Get the project from the field with reflection to suppress the deprecation warning.
|
||||
// If you hate it find a solution yourself and make a PR, I'm getting a bit tired of chasing Gradle updates
|
||||
public static Project getDependencyProject(ProjectDependency projectDependency) {
|
||||
if (projectDependency instanceof DefaultProjectDependency) {
|
||||
try {
|
||||
final Class<DefaultProjectDependency> clazz = DefaultProjectDependency.class;
|
||||
final Field dependencyProject = clazz.getDeclaredField("dependencyProject");
|
||||
dependencyProject.setAccessible(true);
|
||||
return (Project) dependencyProject.get(projectDependency);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
LOGGER.warn("Failed to reflect DefaultProjectDependency", e);
|
||||
}
|
||||
} else if (projectDependency instanceof DelegatingProjectDependency) {
|
||||
try {
|
||||
final Class<DelegatingProjectDependency> clazz = DelegatingProjectDependency.class;
|
||||
final Field delgeate = clazz.getDeclaredField("delegate");
|
||||
delgeate.setAccessible(true);
|
||||
return getDependencyProject((ProjectDependency) delgeate.get(projectDependency));
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
LOGGER.warn("Failed to reflect DelegatingProjectDependency", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Just fallback and trigger the warning, this will break in Gradle 9
|
||||
final Project project = projectDependency.getDependencyProject();
|
||||
LOGGER.warn("Loom was unable to suppress the deprecation warning for ProjectDependency#getDependencyProject, if you are on the latest version of Loom please report this issue to the Loom developers and provide the error above, this WILL stop working in a future Gradle version.");
|
||||
return project;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,11 +268,11 @@ public final class SourceSetHelper {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static File findFileInResource(SourceSet sourceSet, String path) {
|
||||
public static File findFileInResource(Project project, SourceSet sourceSet, String path) {
|
||||
Objects.requireNonNull(project);
|
||||
Objects.requireNonNull(sourceSet);
|
||||
Objects.requireNonNull(path);
|
||||
|
||||
final Project project = getSourceSetProject(sourceSet);
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
|
||||
if (extension.isConfigurationCacheActive()) {
|
||||
@@ -298,9 +298,9 @@ public final class SourceSetHelper {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static File findFirstFileInResource(String path, SourceSet... sourceSets) {
|
||||
public static File findFirstFileInResource(String path, Project project, SourceSet... sourceSets) {
|
||||
for (SourceSet sourceSet : sourceSets) {
|
||||
File file = findFileInResource(sourceSet, path);
|
||||
File file = findFileInResource(project, sourceSet, path);
|
||||
|
||||
if (file != null) {
|
||||
return file;
|
||||
|
||||
@@ -32,7 +32,6 @@ import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.gradle.api.Transformer;
|
||||
import org.gradle.process.internal.JvmOptions;
|
||||
import org.gradle.workers.internal.DaemonForkOptions;
|
||||
import org.gradle.workers.internal.WorkerDaemonClientsManager;
|
||||
|
||||
@@ -88,8 +87,11 @@ public class WorkerDaemonClientsManagerHelper {
|
||||
try {
|
||||
Method getJvmOptions = forkOptions.getClass().getDeclaredMethod("getJvmOptions");
|
||||
getJvmOptions.setAccessible(true);
|
||||
JvmOptions jvmOptions = (JvmOptions) getJvmOptions.invoke(forkOptions);
|
||||
return jvmOptions.getMutableSystemProperties();
|
||||
Object jvmOptions = getJvmOptions.invoke(forkOptions);
|
||||
Method getMutableSystemProperties = jvmOptions.getClass().getDeclaredMethod("getMutableSystemProperties");
|
||||
getMutableSystemProperties.setAccessible(true);
|
||||
//noinspection unchecked
|
||||
return (Map<String, Object>) getMutableSystemProperties.invoke(jvmOptions);
|
||||
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
||||
throw new RuntimeException("Failed to daemon system properties", e);
|
||||
}
|
||||
|
||||
@@ -28,14 +28,16 @@ import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.cache.FileLockManager;
|
||||
import org.gradle.internal.file.Chmod;
|
||||
import org.gradle.internal.remote.internal.RemoteConnection;
|
||||
import org.gradle.internal.remote.internal.inet.TcpOutgoingConnector;
|
||||
import org.gradle.internal.serialize.Serializers;
|
||||
import org.gradle.internal.service.ServiceRegistry;
|
||||
import org.gradle.invocation.DefaultGradle;
|
||||
import org.gradle.launcher.daemon.client.DaemonClientConnection;
|
||||
import org.gradle.launcher.daemon.client.StopDispatcher;
|
||||
import org.gradle.launcher.daemon.protocol.DaemonMessageSerializer;
|
||||
@@ -63,17 +65,17 @@ public final class DaemonUtils {
|
||||
/**
|
||||
* Request the Gradle daemon to stop when it becomes idle.
|
||||
*/
|
||||
public static void tryStopGradleDaemon(Project project) {
|
||||
public static void tryStopGradleDaemon(DaemonUtils.Context context) {
|
||||
try {
|
||||
stopWhenIdle(project);
|
||||
stopWhenIdle(context);
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to request the Gradle demon to stop", t);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static boolean stopWhenIdle(Project project) {
|
||||
DaemonInfo daemonInfo = findCurrentDaemon(project);
|
||||
public static boolean stopWhenIdle(DaemonUtils.Context context) {
|
||||
DaemonInfo daemonInfo = findCurrentDaemon(context);
|
||||
|
||||
if (daemonInfo == null) {
|
||||
return false;
|
||||
@@ -98,14 +100,13 @@ public final class DaemonUtils {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static DaemonInfo findCurrentDaemon(Project project) {
|
||||
private static DaemonInfo findCurrentDaemon(DaemonUtils.Context context) {
|
||||
// Gradle maintains a list of running daemons in a registry.bin file.
|
||||
final Path registryBin = project.getGradle().getGradleUserHomeDir().toPath().resolve("daemon").resolve(GradleVersion.current().getVersion()).resolve("registry.bin");
|
||||
project.getLogger().lifecycle("Looking for daemon in: " + registryBin);
|
||||
final Path registryBin = Path.of(context.getRegistryBin().get());
|
||||
LOGGER.info("Looking for daemon in: {}", registryBin);
|
||||
|
||||
// We can use a PersistentDaemonRegistry to read this
|
||||
final ServiceRegistry services = ((DefaultGradle) project.getGradle()).getServices();
|
||||
final DaemonRegistry registry = new PersistentDaemonRegistry(registryBin.toFile(), services.get(FileLockManager.class), services.get(Chmod.class));
|
||||
final DaemonRegistry registry = new PersistentDaemonRegistry(registryBin.toFile(), context.getFileLockManager(), context.getChmod());
|
||||
|
||||
final long pid = ProcessHandle.current().pid();
|
||||
final List<DaemonInfo> runningDaemons = registry.getAll();
|
||||
@@ -121,4 +122,33 @@ public final class DaemonUtils {
|
||||
LOGGER.warn("Could not find current process in daemon registry: {}", registryBin);
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract static class Context {
|
||||
@Input
|
||||
protected abstract Property<String> getRegistryBin();
|
||||
|
||||
@Inject
|
||||
protected abstract FileLockManager getFileLockManager();
|
||||
|
||||
@Inject
|
||||
protected abstract Chmod getChmod();
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Inject
|
||||
public Context(Project project) {
|
||||
getRegistryBin().set(Context.getRegistryBinPathName(project));
|
||||
}
|
||||
|
||||
public static Context fromProject(Project project) {
|
||||
return project.getObjects().newInstance(Context.class, project);
|
||||
}
|
||||
|
||||
private static String getRegistryBinPathName(Project project) {
|
||||
return project.getGradle().getGradleUserHomeDir().toPath()
|
||||
.resolve("daemon")
|
||||
.resolve(GradleVersion.current().getVersion())
|
||||
.resolve("registry.bin")
|
||||
.toAbsolutePath().toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,17 +61,16 @@ public final class KotlinClasspathService extends Service<KotlinClasspathService
|
||||
|
||||
return createOptions(
|
||||
project,
|
||||
KotlinPluginUtils.getKotlinPluginVersion(project),
|
||||
KotlinPluginUtils.getKotlinMetadataVersion()
|
||||
KotlinPluginUtils.getKotlinPluginVersion(project)
|
||||
);
|
||||
}
|
||||
|
||||
private static Provider<Options> createOptions(Project project, String kotlinVersion, String kotlinMetadataVersion) {
|
||||
private static Provider<Options> createOptions(Project project, String kotlinVersion) {
|
||||
// Create a detached config to resolve the kotlin std lib for the provided version.
|
||||
Configuration detachedConfiguration = project.getConfigurations().detachedConfiguration(
|
||||
project.getDependencies().create("org.jetbrains.kotlin:kotlin-stdlib:" + kotlinVersion),
|
||||
// Load kotlinx-metadata-jvm like this to work around: https://github.com/gradle/gradle/issues/14727
|
||||
project.getDependencies().create("org.jetbrains.kotlinx:kotlinx-metadata-jvm:" + kotlinMetadataVersion)
|
||||
project.getDependencies().create("org.jetbrains.kotlin:kotlin-metadata-jvm:" + kotlinVersion)
|
||||
);
|
||||
|
||||
return TYPE.create(project, options -> {
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import kotlinx.metadata.jvm.KotlinClassMetadata;
|
||||
import org.gradle.api.Project;
|
||||
|
||||
public class KotlinPluginUtils {
|
||||
@@ -56,8 +55,4 @@ public class KotlinPluginUtils {
|
||||
|
||||
return props.getProperty(property);
|
||||
}
|
||||
|
||||
public static String getKotlinMetadataVersion() {
|
||||
return KotlinClassMetadata.class.getPackage().getImplementationVersion().split("-")[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,13 @@
|
||||
|
||||
package net.fabricmc.loom.kotlin.remapping
|
||||
|
||||
import kotlinx.metadata.jvm.KotlinClassMetadata
|
||||
import kotlinx.metadata.jvm.Metadata
|
||||
import org.objectweb.asm.AnnotationVisitor
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.commons.Remapper
|
||||
import org.objectweb.asm.tree.AnnotationNode
|
||||
import org.slf4j.LoggerFactory
|
||||
import kotlin.metadata.jvm.KotlinClassMetadata
|
||||
import kotlin.metadata.jvm.Metadata
|
||||
|
||||
class KotlinClassMetadataRemappingAnnotationVisitor(
|
||||
private val remapper: Remapper,
|
||||
@@ -62,8 +62,14 @@ class KotlinClassMetadataRemappingAnnotationVisitor(
|
||||
"is using (${KotlinVersion.CURRENT}).",
|
||||
)
|
||||
}
|
||||
val metadata = KotlinClassMetadata.readLenient(header)
|
||||
if (metadata.version.major < 1 || (metadata.version.major == 1 && metadata.version.minor < 4)) {
|
||||
logger.warn("$className is not supported by kotlin metadata remapping (version: ${metadata.version})")
|
||||
accept(next)
|
||||
return
|
||||
}
|
||||
|
||||
when (val metadata = KotlinClassMetadata.readLenient(header)) {
|
||||
when (metadata) {
|
||||
is KotlinClassMetadata.Class -> {
|
||||
var klass = metadata.kmClass
|
||||
klass = KotlinClassRemapper(remapper).remap(klass)
|
||||
|
||||
@@ -24,35 +24,35 @@
|
||||
|
||||
package net.fabricmc.loom.kotlin.remapping
|
||||
|
||||
import kotlinx.metadata.ClassName
|
||||
import kotlinx.metadata.ExperimentalContextReceivers
|
||||
import kotlinx.metadata.KmAnnotation
|
||||
import kotlinx.metadata.KmClass
|
||||
import kotlinx.metadata.KmClassifier
|
||||
import kotlinx.metadata.KmConstructor
|
||||
import kotlinx.metadata.KmFlexibleTypeUpperBound
|
||||
import kotlinx.metadata.KmFunction
|
||||
import kotlinx.metadata.KmLambda
|
||||
import kotlinx.metadata.KmPackage
|
||||
import kotlinx.metadata.KmProperty
|
||||
import kotlinx.metadata.KmType
|
||||
import kotlinx.metadata.KmTypeAlias
|
||||
import kotlinx.metadata.KmTypeParameter
|
||||
import kotlinx.metadata.KmTypeProjection
|
||||
import kotlinx.metadata.KmValueParameter
|
||||
import kotlinx.metadata.isLocalClassName
|
||||
import kotlinx.metadata.jvm.JvmFieldSignature
|
||||
import kotlinx.metadata.jvm.JvmMethodSignature
|
||||
import kotlinx.metadata.jvm.annotations
|
||||
import kotlinx.metadata.jvm.fieldSignature
|
||||
import kotlinx.metadata.jvm.getterSignature
|
||||
import kotlinx.metadata.jvm.localDelegatedProperties
|
||||
import kotlinx.metadata.jvm.setterSignature
|
||||
import kotlinx.metadata.jvm.signature
|
||||
import kotlinx.metadata.jvm.syntheticMethodForAnnotations
|
||||
import kotlinx.metadata.jvm.syntheticMethodForDelegate
|
||||
import kotlinx.metadata.jvm.toJvmInternalName
|
||||
import org.objectweb.asm.commons.Remapper
|
||||
import kotlin.metadata.ClassName
|
||||
import kotlin.metadata.ExperimentalContextReceivers
|
||||
import kotlin.metadata.KmAnnotation
|
||||
import kotlin.metadata.KmClass
|
||||
import kotlin.metadata.KmClassifier
|
||||
import kotlin.metadata.KmConstructor
|
||||
import kotlin.metadata.KmFlexibleTypeUpperBound
|
||||
import kotlin.metadata.KmFunction
|
||||
import kotlin.metadata.KmLambda
|
||||
import kotlin.metadata.KmPackage
|
||||
import kotlin.metadata.KmProperty
|
||||
import kotlin.metadata.KmType
|
||||
import kotlin.metadata.KmTypeAlias
|
||||
import kotlin.metadata.KmTypeParameter
|
||||
import kotlin.metadata.KmTypeProjection
|
||||
import kotlin.metadata.KmValueParameter
|
||||
import kotlin.metadata.isLocalClassName
|
||||
import kotlin.metadata.jvm.JvmFieldSignature
|
||||
import kotlin.metadata.jvm.JvmMethodSignature
|
||||
import kotlin.metadata.jvm.annotations
|
||||
import kotlin.metadata.jvm.fieldSignature
|
||||
import kotlin.metadata.jvm.getterSignature
|
||||
import kotlin.metadata.jvm.localDelegatedProperties
|
||||
import kotlin.metadata.jvm.setterSignature
|
||||
import kotlin.metadata.jvm.signature
|
||||
import kotlin.metadata.jvm.syntheticMethodForAnnotations
|
||||
import kotlin.metadata.jvm.syntheticMethodForDelegate
|
||||
import kotlin.metadata.jvm.toJvmInternalName
|
||||
|
||||
@OptIn(ExperimentalContextReceivers::class)
|
||||
class KotlinClassRemapper(private val remapper: Remapper) {
|
||||
|
||||
@@ -29,10 +29,20 @@ import spock.lang.Unroll
|
||||
|
||||
import net.fabricmc.loom.test.util.GradleProjectTestTrait
|
||||
|
||||
import static net.fabricmc.loom.test.LoomTestConstants.PRE_RELEASE_GRADLE
|
||||
import static net.fabricmc.loom.test.LoomTestConstants.STANDARD_TEST_VERSIONS
|
||||
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
|
||||
|
||||
class DataGenerationTest extends Specification implements GradleProjectTestTrait {
|
||||
private static String DEPENDENCIES = """
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:1.20.2"
|
||||
mappings "net.fabricmc:yarn:1.20.2+build.4:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:0.14.23"
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:0.90.0+1.20.2"
|
||||
}
|
||||
"""
|
||||
|
||||
@Unroll
|
||||
def "dataGeneration (gradle #version)"() {
|
||||
setup:
|
||||
@@ -41,14 +51,7 @@ class DataGenerationTest extends Specification implements GradleProjectTestTrait
|
||||
fabricApi {
|
||||
configureDataGeneration()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:1.20.2"
|
||||
mappings "net.fabricmc:yarn:1.20.2+build.4:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:0.14.23"
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:0.90.0+1.20.2"
|
||||
}
|
||||
'''
|
||||
''' + DEPENDENCIES
|
||||
when:
|
||||
def result = gradle.run(task: "runDatagen")
|
||||
|
||||
@@ -80,17 +83,8 @@ class DataGenerationTest extends Specification implements GradleProjectTestTrait
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:1.20.2"
|
||||
mappings "net.fabricmc:yarn:1.20.2+build.4:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:0.14.23"
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:0.90.0+1.20.2"
|
||||
|
||||
modDatagenImplementation fabricApi.module("fabric-data-generation-api-v1", "0.90.0+1.20.2")
|
||||
}
|
||||
|
||||
println("%%" + loom.runs.datagen.configName + "%%")
|
||||
'''
|
||||
''' + DEPENDENCIES
|
||||
when:
|
||||
def result = gradle.run(task: "runDatagen")
|
||||
|
||||
@@ -101,4 +95,111 @@ class DataGenerationTest extends Specification implements GradleProjectTestTrait
|
||||
where:
|
||||
version << STANDARD_TEST_VERSIONS
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def "client dataGeneration (gradle #version)"() {
|
||||
setup:
|
||||
def gradle = gradleProject(project: "minimalBase", version: PRE_RELEASE_GRADLE)
|
||||
gradle.buildGradle << '''
|
||||
fabricApi {
|
||||
configureDataGeneration {
|
||||
client = true
|
||||
}
|
||||
}
|
||||
''' + DEPENDENCIES
|
||||
when:
|
||||
def result = gradle.run(task: "runDatagen")
|
||||
|
||||
then:
|
||||
result.task(":runDatagen").outcome == SUCCESS
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def "client dataGeneration sourceset (gradle #version)"() {
|
||||
setup:
|
||||
def gradle = gradleProject(project: "minimalBase", version: PRE_RELEASE_GRADLE)
|
||||
gradle.buildGradle << '''
|
||||
// Must configure the main mod
|
||||
loom.mods {
|
||||
"example" {
|
||||
sourceSet sourceSets.main
|
||||
}
|
||||
}
|
||||
|
||||
fabricApi {
|
||||
configureDataGeneration {
|
||||
createSourceSet = true
|
||||
createRunConfiguration = true
|
||||
modId = "example-datagen"
|
||||
strictValidation = true
|
||||
client = true
|
||||
}
|
||||
}
|
||||
''' + DEPENDENCIES
|
||||
when:
|
||||
def result = gradle.run(task: "runDatagen")
|
||||
|
||||
then:
|
||||
result.task(":runDatagen").outcome == SUCCESS
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def "split client dataGeneration (gradle #version)"() {
|
||||
setup:
|
||||
def gradle = gradleProject(project: "minimalBase", version: PRE_RELEASE_GRADLE)
|
||||
gradle.buildGradle << '''
|
||||
loom {
|
||||
splitEnvironmentSourceSets()
|
||||
mods {
|
||||
"example" {
|
||||
sourceSet sourceSets.main
|
||||
sourceSet sourceSets.client
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fabricApi {
|
||||
configureDataGeneration {
|
||||
client = true
|
||||
}
|
||||
}
|
||||
''' + DEPENDENCIES
|
||||
when:
|
||||
def result = gradle.run(task: "runDatagen")
|
||||
|
||||
then:
|
||||
result.task(":runDatagen").outcome == SUCCESS
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def "split client dataGeneration sourceset (gradle #version)"() {
|
||||
setup:
|
||||
def gradle = gradleProject(project: "minimalBase", version: PRE_RELEASE_GRADLE)
|
||||
gradle.buildGradle << '''
|
||||
loom {
|
||||
splitEnvironmentSourceSets()
|
||||
mods {
|
||||
"example" {
|
||||
sourceSet sourceSets.main
|
||||
sourceSet sourceSets.client
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fabricApi {
|
||||
configureDataGeneration {
|
||||
createSourceSet = true
|
||||
createRunConfiguration = true
|
||||
modId = "example-datagen"
|
||||
strictValidation = true
|
||||
client = true
|
||||
}
|
||||
}
|
||||
''' + DEPENDENCIES
|
||||
when:
|
||||
def result = gradle.run(task: "runDatagen")
|
||||
|
||||
then:
|
||||
result.task(":runDatagen").outcome == SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait {
|
||||
setup:
|
||||
def gradle = gradleProject(
|
||||
repo: "https://github.com/FabricMC/fabric.git",
|
||||
commit: "41bc64cd617f03d49ecc4a4f7788cb65d465415c",
|
||||
commit: "70277babddfaf52ee30013af94764da19473b3b1",
|
||||
version: version,
|
||||
patch: "fabric_api"
|
||||
)
|
||||
@@ -63,7 +63,7 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait {
|
||||
.replace('id "fabric-loom" version "1.6.11"', 'id "dev.architectury.loom"')
|
||||
.replace('"fabric-loom"', '"dev.architectury.loom"') + mixinApPatch
|
||||
|
||||
def minecraftVersion = "1.21"
|
||||
def minecraftVersion = "1.21.4-pre3"
|
||||
def server = ServerRunner.create(gradle.projectDir, minecraftVersion)
|
||||
.withMod(gradle.getOutputFile("fabric-api-999.0.0.jar"))
|
||||
|
||||
@@ -80,7 +80,7 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait {
|
||||
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:${minecraftVersion}"
|
||||
mappings "net.fabricmc:yarn:${minecraftVersion}+build.1:v2"
|
||||
mappings "net.fabricmc:yarn:${minecraftVersion}+build.2:v2"
|
||||
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:999.0.0"
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ class MultiMcVersionTest extends Specification implements GradleProjectTestTrait
|
||||
def "build (gradle #version)"() {
|
||||
setup:
|
||||
def gradle = gradleProject(project: "multi-mc-versions", version: version)
|
||||
gradle.buildSrc("multiMcVersions", false)
|
||||
|
||||
versions.forEach {
|
||||
// Make dir as its now required by Gradle
|
||||
@@ -58,10 +59,9 @@ class MultiMcVersionTest extends Specification implements GradleProjectTestTrait
|
||||
}
|
||||
|
||||
when:
|
||||
def result = gradle.run(tasks: "build")
|
||||
def result = gradle.run(tasks: "build", isloatedProjects: true, configureOnDemand: true)
|
||||
|
||||
then:
|
||||
result.task(":build").outcome == SUCCESS
|
||||
versions.forEach {
|
||||
result.task(":$it:build").outcome == SUCCESS
|
||||
}
|
||||
@@ -69,4 +69,35 @@ class MultiMcVersionTest extends Specification implements GradleProjectTestTrait
|
||||
where:
|
||||
version << STANDARD_TEST_VERSIONS
|
||||
}
|
||||
|
||||
@Unroll
|
||||
def "configure on demand (gradle #version)"() {
|
||||
setup:
|
||||
def gradle = gradleProject(project: "multi-mc-versions", version: version)
|
||||
gradle.buildSrc("multiMcVersions", false)
|
||||
|
||||
versions.forEach {
|
||||
// Make dir as its now required by Gradle
|
||||
new File(gradle.projectDir, it).mkdir()
|
||||
}
|
||||
|
||||
when:
|
||||
def result = gradle.run(
|
||||
tasks: ":fabric-1.19.3:build",
|
||||
isloatedProjects: true,
|
||||
configureOnDemand: true,
|
||||
// See: https://github.com/gradle/gradle/issues/30401
|
||||
// By default parallel configuration of all projects is preferred.
|
||||
args: [
|
||||
"-Dorg.gradle.internal.isolated-projects.configure-on-demand.tasks=true"
|
||||
])
|
||||
|
||||
then:
|
||||
result.task(":fabric-1.19.3:build").outcome == SUCCESS
|
||||
// Ensure that loom is only loaded once.
|
||||
result.output.count("Fabric Loom:") == 1
|
||||
|
||||
where:
|
||||
version << STANDARD_TEST_VERSIONS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,38 +22,26 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.test.unit
|
||||
package net.fabricmc.loom.test.integration.buildSrc.multiMcVersions
|
||||
|
||||
import org.gradle.api.internal.artifacts.dependencies.DefaultProjectDependency
|
||||
import org.gradle.api.internal.catalog.DelegatingProjectDependency
|
||||
import org.gradle.api.internal.project.ProjectInternal
|
||||
import spock.lang.Specification
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.BasePluginExtension
|
||||
|
||||
import net.fabricmc.loom.util.gradle.GradleUtils
|
||||
class TestPlugin implements Plugin<Project> {
|
||||
@Override
|
||||
void apply(Project project) {
|
||||
project.group = "com.example"
|
||||
project.version = "1.0.0"
|
||||
|
||||
class GradleUtilsTest extends Specification {
|
||||
def "get default project dependency"() {
|
||||
given:
|
||||
def project = Mock(ProjectInternal)
|
||||
def dependency = new DefaultProjectDependency(project, false)
|
||||
|
||||
when:
|
||||
def result = GradleUtils.getDependencyProject(dependency)
|
||||
|
||||
then:
|
||||
result == project
|
||||
project.getExtensions().configure(BasePluginExtension.class) {
|
||||
it.archivesName = project.rootProject.isolated.name + "-" + project.name
|
||||
}
|
||||
|
||||
def "get delegated project dependency"() {
|
||||
given:
|
||||
def project = Mock(ProjectInternal)
|
||||
def dependency = new DefaultProjectDependency(project, true)
|
||||
def delegate = new DelegatingProjectDependency(null, dependency)
|
||||
def minecraftVersion = project.name.substring(7)
|
||||
|
||||
when:
|
||||
def result = GradleUtils.getDependencyProject(delegate)
|
||||
|
||||
then:
|
||||
result == project
|
||||
project.getDependencies().add("minecraft", "com.mojang:minecraft:$minecraftVersion")
|
||||
project.getDependencies().add("mappings", "net.fabricmc:yarn:$minecraftVersion+build.1:v2")
|
||||
project.getDependencies().add("modImplementation", "net.fabricmc:fabric-loader:0.16.9")
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ class TestPlugin implements Plugin<Project> {
|
||||
def future = handler.daemonConnection.thenAccept { it.waitForAndProcessStop() }
|
||||
|
||||
// Stop the daemon
|
||||
def result = DaemonUtils.stopWhenIdle(project)
|
||||
def result = DaemonUtils.stopWhenIdle(DaemonUtils.Context.fromProject(project))
|
||||
|
||||
// Wait for the connection to be processed, this should have already happened, as the above call is blocking
|
||||
future.join()
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
package net.fabricmc.loom.test.unit
|
||||
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import spock.lang.Specification
|
||||
|
||||
import net.fabricmc.loom.util.ProcessUtil
|
||||
@@ -32,7 +31,7 @@ import net.fabricmc.loom.util.ProcessUtil
|
||||
class ProcessUtilTest extends Specification {
|
||||
def "print process info"() {
|
||||
when:
|
||||
def output = new ProcessUtil(LogLevel.DEBUG).printWithParents(ProcessHandle.current())
|
||||
def output = new ProcessUtil(ProcessUtil.ArgumentVisibility.SHOW_SENSITIVE).printWithParents(ProcessHandle.current())
|
||||
|
||||
then:
|
||||
// Just a simple check to see if the output is not empty
|
||||
|
||||
@@ -30,7 +30,6 @@ import org.objectweb.asm.tree.ClassNode
|
||||
import spock.lang.Specification
|
||||
|
||||
import net.fabricmc.loom.util.kotlin.KotlinClasspath
|
||||
import net.fabricmc.loom.util.kotlin.KotlinPluginUtils
|
||||
import net.fabricmc.loom.util.kotlin.KotlinRemapperClassloader
|
||||
import net.fabricmc.tinyremapper.api.TrClass
|
||||
import net.fabricmc.tinyremapper.api.TrEnvironment
|
||||
@@ -38,9 +37,8 @@ import net.fabricmc.tinyremapper.api.TrRemapper
|
||||
|
||||
class KotlinRemapperClassloaderTest extends Specification {
|
||||
private static String KOTLIN_VERSION = KotlinVersion.CURRENT.toString()
|
||||
private static String KOTLIN_METADATA_VERSION = KotlinPluginUtils.kotlinMetadataVersion
|
||||
private static String KOTLIN_URL = "https://repo1.maven.org/maven2/org/jetbrains/kotlin/kotlin-stdlib/${KOTLIN_VERSION}/kotlin-stdlib-${KOTLIN_VERSION}.jar"
|
||||
private static String KOTLIN_METADATA_URL = "https://repo1.maven.org/maven2/org/jetbrains/kotlinx/kotlinx-metadata-jvm/${KOTLIN_METADATA_VERSION}/kotlinx-metadata-jvm-${KOTLIN_METADATA_VERSION}.jar"
|
||||
private static String KOTLIN_METADATA_URL = "https://repo1.maven.org/maven2/org/jetbrains/kotlin/kotlin-metadata-jvm/${KOTLIN_VERSION}/kotlin-metadata-jvm-${KOTLIN_VERSION}.jar"
|
||||
|
||||
def "Test Kotlin Remapper Classloader"() {
|
||||
given:
|
||||
|
||||
@@ -180,6 +180,10 @@ trait GradleProjectTestTrait {
|
||||
args << "-Dorg.gradle.unsafe.isolated-projects=true"
|
||||
}
|
||||
|
||||
if (options.configureOnDemand) {
|
||||
args << "--configure-on-demand"
|
||||
}
|
||||
|
||||
args.addAll(options.tasks ?: [])
|
||||
|
||||
args << "--stacktrace"
|
||||
@@ -278,7 +282,7 @@ trait GradleProjectTestTrait {
|
||||
return file
|
||||
}
|
||||
|
||||
void buildSrc(String name) {
|
||||
void buildSrc(String name, boolean apply = true) {
|
||||
useBuildSrc = true
|
||||
|
||||
def buildSrcDir = new File(projectDir, "buildSrc")
|
||||
@@ -305,6 +309,12 @@ trait GradleProjectTestTrait {
|
||||
rootProject.name='loom-test-plugin'
|
||||
'''
|
||||
|
||||
def sourceSrc = new File("src/test/groovy/net/fabricmc/loom/test/integration/buildSrc/" + name)
|
||||
def targetSrc = new File(buildSrcDir, "src/main/groovy/net/fabricmc/loom/test/integration/buildSrc/" + name)
|
||||
|
||||
FileUtils.copyDirectory(sourceSrc, targetSrc)
|
||||
|
||||
if (apply) {
|
||||
// Patch the new plugin into the end of the plugins block
|
||||
def matcher = buildGradle.text =~ /(?s)plugins \{(?<ids>.*?)}/
|
||||
assert matcher.find()
|
||||
@@ -318,11 +328,7 @@ trait GradleProjectTestTrait {
|
||||
"""
|
||||
|
||||
buildGradle.text = buildGradle.text.replaceAll("(?s)(plugins \\{.*?})", pluginBlock)
|
||||
|
||||
def sourceSrc = new File("src/test/groovy/net/fabricmc/loom/test/integration/buildSrc/" + name)
|
||||
def targetSrc = new File(buildSrcDir, "src/main/groovy/net/fabricmc/loom/test/integration/buildSrc/" + name)
|
||||
|
||||
FileUtils.copyDirectory(sourceSrc, targetSrc)
|
||||
}
|
||||
}
|
||||
|
||||
void writeBuildSrcDeps(GradleRunner runner) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
diff --git a/build.gradle b/build.gradle
|
||||
--- a/build.gradle (revision 41bc64cd617f03d49ecc4a4f7788cb65d465415c)
|
||||
+++ b/build.gradle (date 1718312645477)
|
||||
--- a/build.gradle (revision 70277babddfaf52ee30013af94764da19473b3b1)
|
||||
+++ b/build.gradle (date 1732875235843)
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
def ENV = System.getenv()
|
||||
@@ -36,3 +36,23 @@ diff --git a/build.gradle b/build.gradle
|
||||
}
|
||||
|
||||
def getBranch() {
|
||||
@@ -247,19 +230,6 @@
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
-
|
||||
- afterEvaluate {
|
||||
- // See: https://github.com/FabricMC/fabric-loader/pull/585
|
||||
- def classPathGroups = loom.mods.stream()
|
||||
- .map { modSettings ->
|
||||
- SourceSetHelper.getClasspath(modSettings, getProject()).stream()
|
||||
- .map(File.&getAbsolutePath)
|
||||
- .collect(Collectors.joining(File.pathSeparator))
|
||||
- }
|
||||
- .collect(Collectors.joining(File.pathSeparator+File.pathSeparator))
|
||||
-
|
||||
- systemProperty("fabric.classPathGroups", classPathGroups)
|
||||
- }
|
||||
}
|
||||
|
||||
tasks.withType(ProcessResources).configureEach {
|
||||
|
||||
@@ -3,8 +3,8 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "1.9.22"
|
||||
kotlin("plugin.serialization") version "1.9.22"
|
||||
kotlin("jvm") version "2.0.21"
|
||||
kotlin("plugin.serialization") version "2.0.21"
|
||||
id("dev.architectury.loom")
|
||||
`maven-publish`
|
||||
}
|
||||
@@ -31,8 +31,8 @@ version = "0.0.1"
|
||||
dependencies {
|
||||
minecraft(group = "com.mojang", name = "minecraft", version = "1.16.5")
|
||||
mappings(group = "net.fabricmc", name = "yarn", version = "1.16.5+build.5", classifier = "v2")
|
||||
modImplementation("net.fabricmc:fabric-loader:0.12.12")
|
||||
modImplementation(group = "net.fabricmc", name = "fabric-language-kotlin", version = "1.10.17+kotlin.1.9.22")
|
||||
modImplementation("net.fabricmc:fabric-loader:0.16.9")
|
||||
modImplementation(group = "net.fabricmc", name = "fabric-language-kotlin", version = "1.12.3+kotlin.2.0.21")
|
||||
}
|
||||
|
||||
publishing {
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
plugins {
|
||||
id "java"
|
||||
id 'dev.architectury.loom' apply false
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group = project.maven_group
|
||||
version = project.mod_version
|
||||
}
|
||||
|
||||
ext {
|
||||
yarnMeta = new JsonSlurper().parse(new URL("https://meta.fabricmc.net/v2/versions/yarn"))
|
||||
}
|
||||
|
||||
def getMappingVersion(String mcVersion) {
|
||||
return rootProject.yarnMeta.find { it.gameVersion == mcVersion }.version
|
||||
}
|
||||
|
||||
subprojects {
|
||||
apply plugin: "dev.architectury.loom"
|
||||
|
||||
base {
|
||||
archivesName = rootProject.name + "-" + project.name
|
||||
}
|
||||
|
||||
def minecraft_version = project.name.substring(7)
|
||||
def yarn_mappings = getMappingVersion(minecraft_version)
|
||||
|
||||
dependencies {
|
||||
// To change the versions see the gradle.properties files
|
||||
minecraft "com.mojang:minecraft:$minecraft_version"
|
||||
mappings "net.fabricmc:yarn:$yarn_mappings:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:$loader_version"
|
||||
}
|
||||
|
||||
jar {
|
||||
archiveClassifier.set "dev"
|
||||
}
|
||||
|
||||
// Just use the source from the root project
|
||||
compileJava {
|
||||
source(sourceSets.main.java.srcDirs)
|
||||
}
|
||||
|
||||
processResources {
|
||||
from(rootProject.sourceSets.main.resources)
|
||||
def version = project.version
|
||||
def mcVersion = minecraft_version
|
||||
def loaderVersion = project.loader_version
|
||||
|
||||
inputs.property 'version', version
|
||||
inputs.property 'minecraft_version', mcVersion
|
||||
inputs.property 'loader_version', loaderVersion
|
||||
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand 'version': version, 'minecraft_version': mcVersion, 'loader_version': loaderVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compileJava.enabled = false
|
||||
processResources.enabled = false
|
||||
@@ -1,3 +1,16 @@
|
||||
plugins {
|
||||
id 'fabric-loom' apply false
|
||||
}
|
||||
|
||||
gradle.lifecycle.beforeProject {
|
||||
if (it.rootProject == it) {
|
||||
return
|
||||
}
|
||||
|
||||
apply plugin: 'fabric-loom'
|
||||
apply plugin: 'loom-test-plugin'
|
||||
}
|
||||
|
||||
rootProject.name = "multi-mc-versions"
|
||||
|
||||
// Yes lot of mc version
|
||||
|
||||
Reference in New Issue
Block a user