mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-03-28 12:17:00 -05:00
551 lines
22 KiB
Java
551 lines
22 KiB
Java
/*
|
|
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
|
*
|
|
* Copyright (c) 2016-2023 FabricMC
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
package net.fabricmc.loom.configuration;
|
|
|
|
import static net.fabricmc.loom.util.Constants.Configurations;
|
|
|
|
import java.io.IOException;
|
|
import java.io.UncheckedIOException;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.time.Duration;
|
|
import java.util.Optional;
|
|
import java.util.function.Consumer;
|
|
|
|
import javax.inject.Inject;
|
|
|
|
import org.gradle.api.GradleException;
|
|
import org.gradle.api.Project;
|
|
import org.gradle.api.file.FileCollection;
|
|
import org.gradle.api.logging.Logger;
|
|
import org.gradle.api.logging.Logging;
|
|
import org.gradle.api.plugins.JavaPlugin;
|
|
import org.gradle.api.plugins.JavaPluginExtension;
|
|
import org.gradle.api.tasks.AbstractCopyTask;
|
|
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 net.fabricmc.loom.LoomGradleExtension;
|
|
import net.fabricmc.loom.api.InterfaceInjectionExtensionAPI;
|
|
import net.fabricmc.loom.build.mixin.GroovyApInvoker;
|
|
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.accesstransformer.AccessTransformerJarProcessor;
|
|
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor;
|
|
import net.fabricmc.loom.configuration.ifaceinject.InterfaceInjectionProcessor;
|
|
import net.fabricmc.loom.configuration.mods.ModConfigurationRemapper;
|
|
import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager;
|
|
import net.fabricmc.loom.configuration.processors.ModJavadocProcessor;
|
|
import net.fabricmc.loom.configuration.providers.forge.DependencyProviders;
|
|
import net.fabricmc.loom.configuration.providers.forge.ForgeLibrariesProvider;
|
|
import net.fabricmc.loom.configuration.providers.forge.ForgeProvider;
|
|
import net.fabricmc.loom.configuration.providers.forge.ForgeRunsProvider;
|
|
import net.fabricmc.loom.configuration.providers.forge.ForgeUniversalProvider;
|
|
import net.fabricmc.loom.configuration.providers.forge.ForgeUserdevProvider;
|
|
import net.fabricmc.loom.configuration.providers.forge.PatchProvider;
|
|
import net.fabricmc.loom.configuration.providers.forge.SrgProvider;
|
|
import net.fabricmc.loom.configuration.providers.forge.mcpconfig.McpConfigProvider;
|
|
import net.fabricmc.loom.configuration.providers.forge.minecraft.ForgeMinecraftProvider;
|
|
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory;
|
|
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
|
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMetadataProvider;
|
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
|
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
|
import net.fabricmc.loom.configuration.providers.minecraft.mapped.AbstractMappedMinecraftProvider;
|
|
import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider;
|
|
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MojangMappedMinecraftProvider;
|
|
import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider;
|
|
import net.fabricmc.loom.configuration.providers.minecraft.mapped.SrgMinecraftProvider;
|
|
import net.fabricmc.loom.configuration.sources.ForgeSourcesRemapper;
|
|
import net.fabricmc.loom.extension.MixinExtension;
|
|
import net.fabricmc.loom.util.Checksum;
|
|
import net.fabricmc.loom.util.Constants;
|
|
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.service.ScopedServiceFactory;
|
|
import net.fabricmc.loom.util.service.ServiceFactory;
|
|
|
|
public abstract class CompileConfiguration implements Runnable {
|
|
@Inject
|
|
protected abstract Project getProject();
|
|
|
|
@Inject
|
|
protected abstract TaskContainer getTasks();
|
|
|
|
@Override
|
|
public void run() {
|
|
LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
|
|
|
getTasks().named(JavaPlugin.JAVADOC_TASK_NAME, Javadoc.class).configure(javadoc -> {
|
|
final SourceSet main = SourceSetHelper.getMainSourceSet(getProject());
|
|
javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath()));
|
|
});
|
|
|
|
afterEvaluationWithService((serviceFactory) -> {
|
|
final ConfigContext configContext = new ConfigContextImpl(getProject(), serviceFactory, extension);
|
|
|
|
MinecraftSourceSets.get(getProject()).afterEvaluate(getProject());
|
|
|
|
final boolean previousRefreshDeps = extension.refreshDeps();
|
|
|
|
final LockResult lockResult = acquireProcessLockWaiting(getLockFile());
|
|
|
|
if (lockResult != LockResult.ACQUIRED_CLEAN) {
|
|
getProject().getLogger().lifecycle("Found existing cache lock file ({}), rebuilding loom cache. This may have been caused by a failed or canceled build.", lockResult);
|
|
extension.setRefreshDeps(true);
|
|
}
|
|
|
|
try {
|
|
setupMinecraft(configContext);
|
|
|
|
LoomDependencyManager dependencyManager = new LoomDependencyManager();
|
|
extension.setDependencyManager(dependencyManager);
|
|
dependencyManager.handleDependencies(getProject(), serviceFactory);
|
|
} catch (Exception e) {
|
|
ExceptionUtil.processException(e, getProject());
|
|
disownLock();
|
|
throw ExceptionUtil.createDescriptiveWrapper(RuntimeException::new, "Failed to setup Minecraft", e);
|
|
}
|
|
|
|
releaseLock();
|
|
extension.setRefreshDeps(previousRefreshDeps);
|
|
|
|
MixinExtension mixin = LoomGradleExtension.get(getProject()).getMixin();
|
|
|
|
if (mixin.getUseLegacyMixinAp().get()) {
|
|
setupMixinAp(mixin);
|
|
}
|
|
|
|
configureDecompileTasks(configContext);
|
|
|
|
if (extension.isForgeLike()) {
|
|
if (extension.isDataGenEnabled()) {
|
|
getProject().getExtensions().getByType(JavaPluginExtension.class).getSourceSets().getByName("main").resources(files -> {
|
|
files.srcDir(getProject().file("src/generated/resources"));
|
|
});
|
|
}
|
|
|
|
// TODO: Find a better place for this?
|
|
// This has to be after dependencyManager.handleDependencies() above
|
|
// because of https://github.com/architectury/architectury-loom/issues/72.
|
|
if (!ModConfigurationRemapper.isCIBuild()) {
|
|
try {
|
|
ForgeSourcesRemapper.addBaseForgeSources(getProject(), configContext.serviceFactory());
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
finalizedBy("eclipse", "genEclipseRuns");
|
|
|
|
// Add the "dev" jar to the "namedElements" configuration
|
|
getProject().artifacts(artifactHandler -> artifactHandler.add(Configurations.NAMED_ELEMENTS, getTasks().named("jar")));
|
|
|
|
// Ensure that the encoding is set to UTF-8, no matter what the system default is
|
|
// this fixes some edge cases with special characters not displaying correctly
|
|
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
|
getTasks().withType(AbstractCopyTask.class).configureEach(abstractCopyTask -> abstractCopyTask.setFilteringCharset(StandardCharsets.UTF_8.name()));
|
|
getTasks().withType(JavaCompile.class).configureEach(javaCompile -> javaCompile.getOptions().setEncoding(StandardCharsets.UTF_8.name()));
|
|
|
|
if (extension.isForgeLike()) {
|
|
// Create default mod from main source set
|
|
extension.mods(mods -> {
|
|
final SourceSet main = getProject().getExtensions().getByType(JavaPluginExtension.class).getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME);
|
|
mods.create("main").sourceSet(main);
|
|
});
|
|
}
|
|
|
|
if (getProject().getPluginManager().hasPlugin("org.jetbrains.kotlin.kapt")) {
|
|
// If loom is applied after kapt, then kapt will use the AP arguments too early for loom to pass the arguments we need for mixin.
|
|
throw new IllegalArgumentException("fabric-loom must be applied BEFORE kapt in the plugins { } block.");
|
|
}
|
|
}
|
|
|
|
// This is not thread safe across getProject()s synchronize it here just to be sure, might be possible to move this further down, but for now this will do.
|
|
private synchronized void setupMinecraft(ConfigContext configContext) throws Exception {
|
|
final Project project = configContext.project();
|
|
final LoomGradleExtension extension = configContext.extension();
|
|
|
|
final MinecraftMetadataProvider metadataProvider = MinecraftMetadataProvider.create(configContext);
|
|
|
|
var jarConfiguration = extension.getMinecraftJarConfiguration().get();
|
|
|
|
if (jarConfiguration == MinecraftJarConfiguration.MERGED && !metadataProvider.getVersionMeta().isVersionOrNewer(Constants.RELEASE_TIME_1_3)) {
|
|
jarConfiguration = MinecraftJarConfiguration.LEGACY_MERGED;
|
|
}
|
|
|
|
// Provide the vanilla mc jars
|
|
final MinecraftProvider minecraftProvider = jarConfiguration.createMinecraftProvider(metadataProvider, configContext);
|
|
|
|
if (extension.isForgeLike() && !(minecraftProvider instanceof ForgeMinecraftProvider)) {
|
|
throw new UnsupportedOperationException("Using Forge with split jars is not supported!");
|
|
}
|
|
|
|
extension.setMinecraftProvider(minecraftProvider);
|
|
minecraftProvider.provide();
|
|
|
|
// Created any layered mapping files.
|
|
LayeredMappingsFactory.afterEvaluate(configContext);
|
|
|
|
// This needs to run after MinecraftProvider.initFiles and MinecraftLibraryProvider.provide
|
|
// but before MinecraftPatchedProvider.provide.
|
|
setupDependencyProviders(project, extension);
|
|
|
|
final DependencyInfo mappingsDep = DependencyInfo.create(getProject(), Configurations.MAPPINGS);
|
|
final MappingConfiguration mappingConfiguration = MappingConfiguration.create(getProject(), configContext.serviceFactory(), mappingsDep, minecraftProvider);
|
|
extension.setMappingConfiguration(mappingConfiguration);
|
|
|
|
if (extension.isForgeLike()) {
|
|
ForgeLibrariesProvider.provide(mappingConfiguration, project);
|
|
((ForgeMinecraftProvider) minecraftProvider).getPatchedProvider().provide();
|
|
}
|
|
|
|
mappingConfiguration.setupPost(project);
|
|
mappingConfiguration.applyToProject(getProject(), mappingsDep);
|
|
|
|
if (extension.isForgeLike()) {
|
|
extension.setForgeRunsProvider(ForgeRunsProvider.create(project));
|
|
}
|
|
|
|
if (minecraftProvider instanceof ForgeMinecraftProvider patched) {
|
|
patched.getPatchedProvider().remapJar(configContext.serviceFactory());
|
|
}
|
|
|
|
// Provide the remapped mc jars
|
|
final IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider = jarConfiguration.createIntermediaryMinecraftProvider(project);
|
|
NamedMinecraftProvider<?> namedMinecraftProvider = jarConfiguration.createNamedMinecraftProvider(project);
|
|
|
|
registerGameProcessors(configContext);
|
|
MinecraftJarProcessorManager minecraftJarProcessorManager = MinecraftJarProcessorManager.create(getProject());
|
|
|
|
if (minecraftJarProcessorManager != null) {
|
|
// Wrap the named MC provider for one that will provide the processed jars
|
|
namedMinecraftProvider = jarConfiguration.createProcessedNamedMinecraftProvider(namedMinecraftProvider, minecraftJarProcessorManager);
|
|
}
|
|
|
|
final var provideContext = new AbstractMappedMinecraftProvider.ProvideContext(true, extension.refreshDeps(), configContext);
|
|
|
|
extension.setIntermediaryMinecraftProvider(intermediaryMinecraftProvider);
|
|
intermediaryMinecraftProvider.provide(provideContext);
|
|
|
|
extension.setNamedMinecraftProvider(namedMinecraftProvider);
|
|
namedMinecraftProvider.provide(provideContext);
|
|
|
|
if (extension.isForge()) {
|
|
final SrgMinecraftProvider<?> srgMinecraftProvider = jarConfiguration.createSrgMinecraftProvider(project);
|
|
extension.setSrgMinecraftProvider(srgMinecraftProvider);
|
|
srgMinecraftProvider.provide(provideContext);
|
|
}
|
|
|
|
if (extension.isForgeLike() && extension.getForgeProvider().usesMojangAtRuntime()) {
|
|
final MojangMappedMinecraftProvider<?> mojangMappedMinecraftProvider = jarConfiguration.createMojangMappedMinecraftProvider(project);
|
|
extension.setMojangMappedMinecraftProvider(mojangMappedMinecraftProvider);
|
|
mojangMappedMinecraftProvider.provide(provideContext);
|
|
}
|
|
}
|
|
|
|
private void registerGameProcessors(ConfigContext configContext) {
|
|
final LoomGradleExtension extension = configContext.extension();
|
|
|
|
final boolean enableTransitiveAccessWideners = extension.getEnableTransitiveAccessWideners().get();
|
|
extension.addMinecraftJarProcessor(AccessWidenerJarProcessor.class, "fabric-loom:access-widener", enableTransitiveAccessWideners, extension.getAccessWidenerPath());
|
|
|
|
if (extension.getEnableModProvidedJavadoc().get()) {
|
|
extension.addMinecraftJarProcessor(ModJavadocProcessor.class, "fabric-loom:mod-javadoc");
|
|
}
|
|
|
|
final InterfaceInjectionExtensionAPI interfaceInjection = extension.getInterfaceInjection();
|
|
|
|
if (interfaceInjection.isEnabled()) {
|
|
extension.addMinecraftJarProcessor(InterfaceInjectionProcessor.class, "fabric-loom:interface-inject", interfaceInjection.getEnableDependencyInterfaceInjection().get());
|
|
}
|
|
|
|
if (extension.isForgeLike()) {
|
|
FileCollection accessTransformers;
|
|
|
|
if (extension.isNeoForge()) {
|
|
accessTransformers = extension.getNeoForge().getAccessTransformers();
|
|
} else {
|
|
accessTransformers = extension.getForge().getAccessTransformers();
|
|
}
|
|
|
|
extension.addMinecraftJarProcessor(AccessTransformerJarProcessor.class, "loom:access-transformer", configContext.project(), accessTransformers);
|
|
}
|
|
}
|
|
|
|
private void setupMixinAp(MixinExtension mixin) {
|
|
mixin.init();
|
|
|
|
// Disable some things used by log4j via the mixin AP that prevent it from being garbage collected
|
|
System.setProperty("log4j2.disable.jmx", "true");
|
|
System.setProperty("log4j.shutdownHookEnabled", "false");
|
|
System.setProperty("log4j.skipJansi", "true");
|
|
|
|
getProject().getLogger().info("Configuring compiler arguments for Java");
|
|
|
|
new JavaApInvoker(getProject()).configureMixin();
|
|
|
|
if (getProject().getPluginManager().hasPlugin("scala")) {
|
|
getProject().getLogger().info("Configuring compiler arguments for Scala");
|
|
new ScalaApInvoker(getProject()).configureMixin();
|
|
}
|
|
|
|
if (getProject().getPluginManager().hasPlugin("org.jetbrains.kotlin.kapt")) {
|
|
getProject().getLogger().info("Configuring compiler arguments for Kapt plugin");
|
|
new KaptApInvoker(getProject()).configureMixin();
|
|
}
|
|
|
|
if (getProject().getPluginManager().hasPlugin("groovy")) {
|
|
getProject().getLogger().info("Configuring compiler arguments for Groovy");
|
|
new GroovyApInvoker(getProject()).configureMixin();
|
|
}
|
|
}
|
|
|
|
private void configureDecompileTasks(ConfigContext configContext) {
|
|
final LoomGradleExtension extension = configContext.extension();
|
|
|
|
extension.getMinecraftJarConfiguration().get()
|
|
.createDecompileConfiguration(getProject())
|
|
.afterEvaluation();
|
|
}
|
|
|
|
private LockFile getLockFile() {
|
|
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
|
final Path cacheDirectory = extension.getFiles().getUserCache().toPath();
|
|
final String pathHash = Checksum.projectHash(getProject());
|
|
return new LockFile(
|
|
cacheDirectory.resolve("." + pathHash + ".lock"),
|
|
"Lock for cache='%s', project='%s'".formatted(
|
|
cacheDirectory, getProject().absoluteProjectPath(getProject().getPath())
|
|
)
|
|
);
|
|
}
|
|
|
|
record LockFile(Path file, String description) {
|
|
@Override
|
|
public String toString() {
|
|
return this.description;
|
|
}
|
|
}
|
|
|
|
enum LockResult {
|
|
// acquired immediately or after waiting for another process to release
|
|
ACQUIRED_CLEAN,
|
|
// already owned by current pid
|
|
ACQUIRED_ALREADY_OWNED,
|
|
// acquired due to current owner not existing
|
|
ACQUIRED_PREVIOUS_OWNER_MISSING,
|
|
// acquired due to previous owner disowning the lock
|
|
ACQUIRED_PREVIOUS_OWNER_DISOWNED
|
|
}
|
|
|
|
private LockResult acquireProcessLockWaiting(LockFile lockFile) {
|
|
// one hour
|
|
return this.acquireProcessLockWaiting(lockFile, getDefaultTimeout());
|
|
}
|
|
|
|
private LockResult acquireProcessLockWaiting(LockFile lockFile, Duration timeout) {
|
|
try {
|
|
return this.acquireProcessLockWaiting_(lockFile, timeout);
|
|
} catch (final IOException e) {
|
|
throw new RuntimeException("Exception acquiring lock " + lockFile, e);
|
|
}
|
|
}
|
|
|
|
// Returns true if our process already owns the lock
|
|
@SuppressWarnings("BusyWait")
|
|
private LockResult acquireProcessLockWaiting_(LockFile lockFile, Duration timeout) throws IOException {
|
|
final long timeoutMs = timeout.toMillis();
|
|
final Logger logger = Logging.getLogger("loom_acquireProcessLockWaiting");
|
|
final long currentPid = ProcessHandle.current().pid();
|
|
boolean abrupt = false;
|
|
boolean disowned = false;
|
|
|
|
if (Files.exists(lockFile.file)) {
|
|
long lockingProcessId = -1;
|
|
|
|
try {
|
|
String lockValue = Files.readString(lockFile.file);
|
|
|
|
if ("disowned".equals(lockValue)) {
|
|
disowned = true;
|
|
} else {
|
|
lockingProcessId = Long.parseLong(lockValue);
|
|
logger.lifecycle("\"{}\" is currently held by pid '{}'.", lockFile, lockingProcessId);
|
|
}
|
|
} catch (final Exception ignored) {
|
|
// ignored
|
|
}
|
|
|
|
if (lockingProcessId == currentPid) {
|
|
return LockResult.ACQUIRED_ALREADY_OWNED;
|
|
}
|
|
|
|
Optional<ProcessHandle> handle = ProcessHandle.of(lockingProcessId);
|
|
|
|
if (disowned) {
|
|
logger.lifecycle("Previous process has disowned the lock due to abrupt termination.");
|
|
Files.deleteIfExists(lockFile.file);
|
|
} else if (handle.isEmpty()) {
|
|
logger.lifecycle("Locking process does not exist, assuming abrupt termination and deleting lock file.");
|
|
Files.deleteIfExists(lockFile.file);
|
|
abrupt = true;
|
|
} else {
|
|
ProcessUtil processUtil = ProcessUtil.create(getProject());
|
|
logger.lifecycle(processUtil.printWithParents(handle.get()));
|
|
logger.lifecycle("Waiting for lock to be released...");
|
|
long sleptMs = 0;
|
|
|
|
while (Files.exists(lockFile.file)) {
|
|
try {
|
|
Thread.sleep(100);
|
|
} catch (final InterruptedException e) {
|
|
Thread.currentThread().interrupt();
|
|
}
|
|
|
|
sleptMs += 100;
|
|
|
|
if (sleptMs >= 1000 * 60 && sleptMs % (1000 * 60) == 0L) {
|
|
logger.lifecycle(
|
|
"""
|
|
Have been waiting on "{}" held by pid '{}' for {} minute(s).
|
|
If this persists for an unreasonable length of time, kill this process, run './gradlew --stop' and then try again.""",
|
|
lockFile, lockingProcessId, sleptMs / 1000 / 60
|
|
);
|
|
}
|
|
|
|
if (sleptMs >= timeoutMs) {
|
|
throw new GradleException("Have been waiting on lock file '%s' for %s ms. Giving up as timeout is %s ms."
|
|
.formatted(lockFile, sleptMs, timeoutMs));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!Files.exists(lockFile.file.getParent())) {
|
|
Files.createDirectories(lockFile.file.getParent());
|
|
}
|
|
|
|
Files.writeString(lockFile.file, String.valueOf(currentPid));
|
|
|
|
if (disowned) {
|
|
return LockResult.ACQUIRED_PREVIOUS_OWNER_DISOWNED;
|
|
} else if (abrupt) {
|
|
return LockResult.ACQUIRED_PREVIOUS_OWNER_MISSING;
|
|
}
|
|
|
|
return LockResult.ACQUIRED_CLEAN;
|
|
}
|
|
|
|
private static Duration getDefaultTimeout() {
|
|
if (System.getenv("CI") != null) {
|
|
// Set a small timeout on CI, as it's unlikely going to unlock.
|
|
return Duration.ofMinutes(1);
|
|
}
|
|
|
|
return Duration.ofHours(1);
|
|
}
|
|
|
|
// When we fail to configure, write "disowned" to the lock file to release it from this process
|
|
// This allows the next run to rebuild without waiting for this process to exit
|
|
private void disownLock() {
|
|
final Path lock = getLockFile().file;
|
|
|
|
try {
|
|
Files.writeString(lock, "disowned");
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
private void releaseLock() {
|
|
final Path lock = getLockFile().file;
|
|
|
|
if (!Files.exists(lock)) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
Files.delete(lock);
|
|
} catch (IOException e1) {
|
|
try {
|
|
// If we failed to delete the lock file, moving it before trying to delete it may help.
|
|
final Path del = lock.resolveSibling(lock.getFileName() + ".del");
|
|
Files.move(lock, del);
|
|
Files.delete(del);
|
|
} catch (IOException e2) {
|
|
var exception = new UncheckedIOException("Failed to release getProject() configuration lock", e2);
|
|
exception.addSuppressed(e1);
|
|
throw exception;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void finalizedBy(String a, String b) {
|
|
getTasks().named(a).configure(task -> task.finalizedBy(getTasks().named(b)));
|
|
}
|
|
|
|
public static void setupDependencyProviders(Project project, LoomGradleExtension extension) {
|
|
DependencyProviders dependencyProviders = new DependencyProviders();
|
|
extension.setDependencyProviders(dependencyProviders);
|
|
|
|
if (extension.isForgeLike()) {
|
|
dependencyProviders.addProvider(new ForgeProvider(project));
|
|
dependencyProviders.addProvider(new ForgeUserdevProvider(project));
|
|
}
|
|
|
|
if (extension.shouldGenerateSrgTiny()) {
|
|
dependencyProviders.addProvider(new SrgProvider(project));
|
|
}
|
|
|
|
if (extension.isForgeLike()) {
|
|
dependencyProviders.addProvider(new McpConfigProvider(project));
|
|
dependencyProviders.addProvider(new PatchProvider(project));
|
|
dependencyProviders.addProvider(new ForgeUniversalProvider(project));
|
|
}
|
|
|
|
dependencyProviders.handleDependencies(project);
|
|
}
|
|
|
|
private void afterEvaluationWithService(Consumer<ServiceFactory> consumer) {
|
|
GradleUtils.afterSuccessfulEvaluation(getProject(), () -> {
|
|
try (var serviceFactory = new ScopedServiceFactory()) {
|
|
consumer.accept(serviceFactory);
|
|
} catch (IOException e) {
|
|
throw new UncheckedIOException(e);
|
|
}
|
|
});
|
|
}
|
|
}
|