mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-04-02 21:47:42 -05:00
Make ExceptionUtil & DaemonUtils config cache safe. (#1223)
* Make ExceptionUtil & DaemonUtils config cache safe. * Fix tests * Fix build
This commit is contained in:
@@ -72,6 +72,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;
|
||||
|
||||
@@ -112,7 +113,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);
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ 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;
|
||||
@@ -196,6 +197,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();
|
||||
@@ -250,6 +254,8 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -267,7 +273,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);
|
||||
}
|
||||
|
||||
@@ -300,7 +306,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
runWithCache(fs.getRoot());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ExceptionUtil.processException(e, getProject());
|
||||
ExceptionUtil.processException(e, getDaemonUtilsContext().get());
|
||||
throw ExceptionUtil.createDescriptiveWrapper(RuntimeException::new, "Failed to decompile", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user