Skip to content

Commit

Permalink
Enable configuration cache for most tests by default (#1162)
Browse files Browse the repository at this point in the history
* Enable configuration cache for all tests by default

* Support config cache in test projects

* Some config cache test fixes

* Config caching for run game tasks

* Problems for later

* More problems for later

* Bump min idea version, and remove version check.

* Untested client entries service

* Fixes
  • Loading branch information
modmuss50 authored Aug 30, 2024
1 parent 9157c22 commit f3a9a49
Show file tree
Hide file tree
Showing 35 changed files with 330 additions and 176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
public class LoomGradlePluginBootstrap implements Plugin<PluginAware> {
private static final String MIN_SUPPORTED_GRADLE_VERSION = "8.10";
private static final int MIN_SUPPORTED_MAJOR_JAVA_VERSION = 17;
private static final int MIN_SUPPORTED_MAJOR_IDEA_VERSION = 2021;
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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ private void makeNestableJar(final File input, final File output, final String m
}
}

protected record Metadata(String group, String name, String version, @Nullable String classifier) implements Serializable {
public record Metadata(String group, String name, String version, @Nullable String classifier) implements Serializable {
@Override
public String classifier() {
if (classifier == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public class RunConfig {
public String environment;
public List<String> vmArgs = new ArrayList<>();
public List<String> programArgs = new ArrayList<>();
public SourceSet sourceSet;
public transient SourceSet sourceSet;
public Map<String, Object> environmentVariables;
public String projectName;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ public IdeaSyncTask() {
// Always re-run this task.
getOutputs().upToDateWhen(element -> false);
setGroup(Constants.TaskGroup.IDE);

notCompatibleWithConfigurationCache("Not yet supported");
}

@TaskAction
Expand Down Expand Up @@ -112,10 +114,6 @@ private void generateRunConfigs() throws IOException {
}

private void setClasspathModifications(Path runConfig, List<String> exclusions) throws IOException {
if (!IdeaUtils.supportsCustomizableClasspath()) {
return;
}

final String inputXml = Files.readString(runConfig, StandardCharsets.UTF_8);
final String outputXml;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@

package net.fabricmc.loom.configuration.ide.idea;

import java.util.Objects;

import org.gradle.api.Project;

import net.fabricmc.loom.util.gradle.SourceSetReference;
Expand All @@ -35,18 +33,6 @@ public static boolean isIdeaSync() {
return Boolean.parseBoolean(System.getProperty("idea.sync.active", "false"));
}

public static String getIdeaVersion() {
return Objects.requireNonNull(System.getProperty("idea.version"), "Could not get idea version");
}

// 2021.3 or newer
public static boolean supportsCustomizableClasspath() {
final String[] split = getIdeaVersion().split("\\.");
final int major = Integer.parseInt(split[0]);
final int minor = Integer.parseInt(split[1]);
return major > 2021 || (major == 2021 && minor >= 3);
}

public static String getIdeaModuleName(SourceSetReference reference) {
Project project = reference.project();
String module = project.getName() + "." + reference.sourceSet().getName();
Expand Down
62 changes: 26 additions & 36 deletions src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,12 @@

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.jar.Manifest;

import javax.inject.Inject;
Expand All @@ -51,10 +48,10 @@
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.bundling.ZipEntryCompression;
import org.gradle.build.event.BuildEventsListenerRegistry;
import org.gradle.jvm.tasks.Jar;
import org.gradle.workers.WorkAction;
import org.gradle.workers.WorkParameters;
Expand All @@ -64,11 +61,13 @@

import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.task.service.ClientEntriesService;
import net.fabricmc.loom.task.service.JarManifestService;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.ZipReprocessorUtil;
import net.fabricmc.loom.util.ZipUtils;
import net.fabricmc.loom.util.gradle.SourceSetHelper;
import net.fabricmc.loom.util.service.ScopedServiceFactory;

public abstract class AbstractRemapJarTask extends Jar {
@InputFile
Expand All @@ -86,9 +85,6 @@ public abstract class AbstractRemapJarTask extends Jar {
@Inject
protected abstract WorkerExecutor getWorkerExecutor();

@Inject
protected abstract BuildEventsListenerRegistry getBuildEventsListenerRegistry();

@Input
public abstract Property<Boolean> getIncludesClientOnlyClasses();

Expand All @@ -104,6 +100,10 @@ public abstract class AbstractRemapJarTask extends Jar {
@ApiStatus.Internal
public abstract Property<String> getJarType();

@Nested
@Optional
protected abstract Property<ClientEntriesService.Options> getClientEntriesServiceOptions();

private final Provider<JarManifestService> jarManifestServiceProvider;

@Inject
Expand All @@ -113,6 +113,15 @@ public AbstractRemapJarTask() {
getIncludesClientOnlyClasses().convention(false).finalizeValueOnRead();
getJarType().finalizeValueOnRead();

getClientEntriesServiceOptions().set(getIncludesClientOnlyClasses().flatMap(clientOnlyEntries -> {
if (clientOnlyEntries) {
return getClientOnlyEntriesOptionsProvider(getClientSourceSet());
}

// Empty
return getProject().getObjects().property(ClientEntriesService.Options.class);
}));

jarManifestServiceProvider = JarManifestService.get(getProject());
usesService(jarManifestServiceProvider);
}
Expand All @@ -134,7 +143,15 @@ public final <P extends AbstractRemapParams> void submitWork(Class<? extends Abs
params.getEntryCompression().set(getEntryCompression());

if (getIncludesClientOnlyClasses().get()) {
final List<String> clientOnlyEntries = new ArrayList<>(getClientOnlyEntries(getClientSourceSet()));
final List<String> clientOnlyEntries;

try (var serviceFactory = new ScopedServiceFactory()) {
ClientEntriesService<ClientEntriesService.Options> service = serviceFactory.get(getClientEntriesServiceOptions());
clientOnlyEntries = new ArrayList<>(service.getClientOnlyEntries());
} catch (IOException e) {
throw new RuntimeException(e);
}

clientOnlyEntries.addAll(getAdditionalClientOnlyEntries().get());
Collections.sort(clientOnlyEntries);
applyClientOnlyManifestAttributes(params, clientOnlyEntries);
Expand All @@ -149,7 +166,7 @@ public final <P extends AbstractRemapParams> void submitWork(Class<? extends Abs
});
}

protected abstract List<String> getClientOnlyEntries(SourceSet sourceSet);
protected abstract Provider<? extends ClientEntriesService.Options> getClientOnlyEntriesOptionsProvider(SourceSet clientSourceSet);

public interface AbstractRemapParams extends WorkParameters {
RegularFileProperty getInputFile();
Expand Down Expand Up @@ -229,33 +246,6 @@ public RegularFileProperty getInput() {
return getInputFile();
}

public static List<String> getRootPaths(Set<File> files) {
return files.stream()
.map(root -> {
String rootPath = root.getAbsolutePath().replace("\\", "/");

if (rootPath.charAt(rootPath.length() - 1) != '/') {
rootPath += '/';
}

return rootPath;
}).toList();
}

public static Function<File, String> relativePath(List<String> rootPaths) {
return file -> {
String s = file.getAbsolutePath().replace("\\", "/");

for (String rootPath : rootPaths) {
if (s.startsWith(rootPath)) {
s = s.substring(rootPath.length());
}
}

return s;
};
}

@ApiStatus.Internal
@Internal
protected LoomGradleExtension getLoomExtension() {
Expand Down
75 changes: 49 additions & 26 deletions src/main/java/net/fabricmc/loom/task/AbstractRunTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,41 @@
import org.gradle.api.Project;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.FileCollection;
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;
import org.gradle.api.tasks.JavaExec;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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();
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRunTask.class);

@Input
protected abstract Property<String> getInternalRunDir();
@Input
protected abstract MapProperty<String, Object> getInternalEnvironmentVars();
@Input
protected abstract ListProperty<String> getInternalJvmArgs();
@Input
protected abstract Property<Boolean> getUseArgFile();
@Input
protected abstract Property<String> getProjectDir();

private final Provider<RunConfig> config;
// 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
private final ConfigurableFileCollection classpath = getProject().getObjects().fileCollection();
@InputFiles
protected abstract ConfigurableFileCollection getInternalClasspath();

// Prevent Gradle from running two run tasks in parallel
@ServiceReference(SyncTaskBuildService.NAME)
Expand All @@ -65,12 +83,23 @@ public AbstractRunTask(Function<Project, RunConfig> configProvider) {
super();
setGroup(Constants.TaskGroup.FABRIC);

this.config = getProject().provider(() -> configProvider.apply(getProject()));
final Provider<RunConfig> config = getProject().provider(() -> configProvider.apply(getProject()));

getInternalClasspath().from(config.map(runConfig -> runConfig.sourceSet.getRuntimeClasspath()
.filter(new LibraryFilter(
config.get().getExcludedLibraryPaths(getProject()),
config.get().configName)
)));

classpath.from(config.map(runConfig -> runConfig.sourceSet.getRuntimeClasspath().filter(File::exists).filter(new LibraryFilter())));
getArgumentProviders().add(() -> config.get().programArgs);
getMainClass().set(config.map(runConfig -> runConfig.mainClass));
getJvmArguments().addAll(getProject().provider(this::getGameJvmArgs));

getInternalRunDir().set(config.map(runConfig -> runConfig.runDir));
getInternalEnvironmentVars().set(config.map(runConfig -> runConfig.environmentVariables));
getInternalJvmArgs().set(config.map(runConfig -> runConfig.vmArgs));
getUseArgFile().set(getProject().provider(this::canUseArgFile));
getProjectDir().set(getProject().getProjectDir().getAbsolutePath());
}

private boolean canUseArgFile() {
Expand All @@ -90,18 +119,18 @@ private boolean canPathBeASCIIEncoded() {

@Override
public void exec() {
if (canUseArgFile()) {
getProject().getLogger().debug("Using arg file for {}", getName());
if (getUseArgFile().get()) {
LOGGER.debug("Using arg file for {}", getName());
// We're using an arg file, pass an empty classpath to the super JavaExec.
super.setClasspath(getProject().files());
super.setClasspath(getObjectFactory().fileCollection());
} else {
getProject().getLogger().debug("Using bare classpath for {}", getName());
LOGGER.debug("Using bare classpath for {}", getName());
// The classpath is passed normally, so pass the full classpath to the super JavaExec.
super.setClasspath(classpath);
super.setClasspath(getInternalClasspath());
}

setWorkingDir(new File(getProject().getProjectDir(), config.get().runDir));
environment(config.get().environmentVariables);
setWorkingDir(new File(getProjectDir().get(), getInternalRunDir().get()));
environment(getInternalEnvironmentVars().get());

super.exec();
}
Expand All @@ -118,11 +147,11 @@ public void setWorkingDir(File dir) {
private List<String> getGameJvmArgs() {
final List<String> args = new ArrayList<>();

if (canUseArgFile()) {
final String content = "-classpath\n" + this.classpath.getFiles().stream()
if (getUseArgFile().get()) {
final String content = "-classpath\n" + this.getInternalClasspath().getFiles().stream()
.map(File::getAbsolutePath)
.map(AbstractRunTask::quoteArg)
.collect(Collectors.joining(System.getProperty("path.separator")));
.collect(Collectors.joining(File.pathSeparator));

try {
final Path argsFile = Files.createTempFile("loom-classpath", ".args");
Expand All @@ -133,7 +162,7 @@ private List<String> getGameJvmArgs() {
}
}

args.addAll(config.get().vmArgs);
args.addAll(getInternalJvmArgs().get());
return args;
}

Expand Down Expand Up @@ -183,32 +212,26 @@ public static boolean containsAnyChar(final @NotNull String value, final @NotNul

@Override
public @NotNull JavaExec setClasspath(@NotNull FileCollection classpath) {
this.classpath.setFrom(classpath);
this.getInternalClasspath().setFrom(classpath);
return this;
}

@Override
public @NotNull JavaExec classpath(Object @NotNull... paths) {
this.classpath.from(paths);
this.getInternalClasspath().from(paths);
return this;
}

@Override
public @NotNull FileCollection getClasspath() {
return this.classpath;
return this.getInternalClasspath();
}

private class LibraryFilter implements Spec<File> {
private List<String> excludedLibraryPaths = null;

public record LibraryFilter(List<String> excludedLibraryPaths, String configName) implements Spec<File> {
@Override
public boolean isSatisfiedBy(File element) {
if (excludedLibraryPaths == null) {
excludedLibraryPaths = config.get().getExcludedLibraryPaths(getProject());
}

if (excludedLibraryPaths.contains(element.getAbsolutePath())) {
getProject().getLogger().debug("Excluding library {} from {} run config", element.getName(), config.get().configName);
LOGGER.debug("Excluding library {} from {} run config", element.getName(), configName);
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
Expand All @@ -53,6 +55,11 @@ public abstract class GenVsCodeProjectTask extends AbstractLoomTask {
@ServiceReference(SyncTaskBuildService.NAME)
abstract Property<SyncTaskBuildService> getSyncTask();

@Inject
public GenVsCodeProjectTask() {
notCompatibleWithConfigurationCache("Not yet supported");
}

@TaskAction
public void genRuns() throws IOException {
final Path projectDir = getProject().getRootDir().toPath().resolve(".vscode");
Expand Down
Loading

0 comments on commit f3a9a49

Please sign in to comment.