From 0421559786f4b373d4e61ba9c2a74304ebded9cf Mon Sep 17 00:00:00 2001 From: Marc Hermans Date: Sat, 25 Nov 2023 22:47:32 +0100 Subject: [PATCH] Implement support for dynamic runtime dependencies (#52) * Implement dependency handling for runtime only dependencies. * Fix several issues caused by the latest changes. --- .../gradle/common/CommonProjectPlugin.java | 11 ++- .../run/ConfigurationRunDependencyImpl.java | 39 +++++++++++ .../runs/run/DependencyHandlerImpl.java | 6 ++ .../common/runs/run/RunDependencyImpl.java | 10 ++- .../definition/CommonRuntimeDefinition.java | 5 +- .../gradle/common/util/run/RunsUtil.java | 14 +++- .../common/runs/run/DependencyHandler.groovy | 9 +++ .../definition/NeoFormRuntimeDefinition.java | 4 +- .../extensions/DynamicProjectExtension.java | 20 +++--- .../RuntimeDevRuntimeDefinition.java | 4 +- .../definition/UserDevRuntimeDefinition.java | 70 +++++++++++-------- .../runtime/VanillaRuntimeDefinition.java | 4 +- 12 files changed, 144 insertions(+), 52 deletions(-) create mode 100644 common/src/main/java/net/neoforged/gradle/common/runs/run/ConfigurationRunDependencyImpl.java diff --git a/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java b/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java index c87ce4924..493ee0db1 100644 --- a/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java +++ b/common/src/main/java/net/neoforged/gradle/common/CommonProjectPlugin.java @@ -35,7 +35,9 @@ import org.gradle.plugins.ide.idea.IdeaPlugin; import org.jetbrains.gradle.ext.IdeaExtPlugin; +import java.util.HashSet; import java.util.Optional; +import java.util.Set; public class CommonProjectPlugin implements Plugin { @@ -134,14 +136,21 @@ private void applyAfterEvaluate(final Project project) { if (run.getConfigureFromDependencies().get()) { final RunImpl runImpl = (RunImpl) run; + + final Set> definitionSet = new HashSet<>(); + runImpl.getModSources().get().forEach(sourceSet -> { try { final Optional> definition = TaskDependencyUtils.findRuntimeDefinition(project, sourceSet); - definition.ifPresent(def -> def.configureRun(runImpl)); + definition.ifPresent(definitionSet::add); } catch (MultipleDefinitionsFoundException e) { throw new RuntimeException("Failed to configure run: " + run.getName() + " there are multiple runtime definitions found for the source set: " + sourceSet.getName(), e); } }); + + definitionSet.forEach(definition -> { + definition.configureRun(runImpl); + }); } } })); diff --git a/common/src/main/java/net/neoforged/gradle/common/runs/run/ConfigurationRunDependencyImpl.java b/common/src/main/java/net/neoforged/gradle/common/runs/run/ConfigurationRunDependencyImpl.java new file mode 100644 index 000000000..403f99720 --- /dev/null +++ b/common/src/main/java/net/neoforged/gradle/common/runs/run/ConfigurationRunDependencyImpl.java @@ -0,0 +1,39 @@ +package net.neoforged.gradle.common.runs.run; + +import net.neoforged.gradle.dsl.common.runs.run.RunDependency; +import net.neoforged.gradle.dsl.common.util.ConfigurationUtils; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.ResolvedConfiguration; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.provider.Property; + +import javax.inject.Inject; + +public abstract class ConfigurationRunDependencyImpl implements RunDependency { + + private final Project project; + + @Inject + public ConfigurationRunDependencyImpl(Project project, Configuration dependency) { + getIdentity().convention(dependency.toString()); + getDependency().from(project.provider(() -> { + final ResolvedConfiguration resolvedConfiguration = dependency.getResolvedConfiguration(); + final ConfigurableFileCollection files = project.files(); + return files.from(resolvedConfiguration.getFiles()); + })); + this.project = project; + } + + @Override + public Project getProject() { + return project; + } + + @Override + public abstract ConfigurableFileCollection getDependency(); + + @Override + public abstract Property getIdentity(); +} diff --git a/common/src/main/java/net/neoforged/gradle/common/runs/run/DependencyHandlerImpl.java b/common/src/main/java/net/neoforged/gradle/common/runs/run/DependencyHandlerImpl.java index 5f85f61de..a41eb40b3 100644 --- a/common/src/main/java/net/neoforged/gradle/common/runs/run/DependencyHandlerImpl.java +++ b/common/src/main/java/net/neoforged/gradle/common/runs/run/DependencyHandlerImpl.java @@ -4,6 +4,7 @@ import net.neoforged.gradle.dsl.common.runs.run.RunDependency; import org.gradle.api.Action; import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; import javax.inject.Inject; @@ -70,4 +71,9 @@ public RunDependency project(Map notation) { final Dependency dependency = project.getDependencies().project(notation); return project.getObjects().newInstance(RunDependencyImpl.class, project, dependency); } + + @Override + public RunDependency configuration(Configuration notation) { + return project.getObjects().newInstance(ConfigurationRunDependencyImpl.class, project, notation); + } } diff --git a/common/src/main/java/net/neoforged/gradle/common/runs/run/RunDependencyImpl.java b/common/src/main/java/net/neoforged/gradle/common/runs/run/RunDependencyImpl.java index 501c82b7f..5eff29f64 100644 --- a/common/src/main/java/net/neoforged/gradle/common/runs/run/RunDependencyImpl.java +++ b/common/src/main/java/net/neoforged/gradle/common/runs/run/RunDependencyImpl.java @@ -13,6 +13,8 @@ public abstract class RunDependencyImpl implements RunDependency { + private final Project project; + @Inject public RunDependencyImpl(Project project, Dependency dependency) { getIdentity().convention(dependency.toString()); @@ -22,8 +24,14 @@ public RunDependencyImpl(Project project, Dependency dependency) { final ConfigurableFileCollection files = project.files(); return files.from(resolvedConfiguration.getFiles()); })); + this.project = project; } - + + @Override + public Project getProject() { + return project; + } + @Override public abstract ConfigurableFileCollection getDependency(); diff --git a/common/src/main/java/net/neoforged/gradle/common/runtime/definition/CommonRuntimeDefinition.java b/common/src/main/java/net/neoforged/gradle/common/runtime/definition/CommonRuntimeDefinition.java index 08a8d1fb8..9c3ff6c14 100644 --- a/common/src/main/java/net/neoforged/gradle/common/runtime/definition/CommonRuntimeDefinition.java +++ b/common/src/main/java/net/neoforged/gradle/common/runtime/definition/CommonRuntimeDefinition.java @@ -23,7 +23,6 @@ import org.jetbrains.annotations.Nullable; import java.io.File; -import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; @@ -172,7 +171,7 @@ public VersionJson getVersionJson() { } public void configureRun(RunImpl run) { - final Map runtimeInterpolationData = buildRunInterpolationData(); + final Map runtimeInterpolationData = buildRunInterpolationData(run); final Map workingInterpolationData = new HashMap<>(runtimeInterpolationData); workingInterpolationData.put("source_roots", RunsUtil.buildGradleModClasses(run.getModSources()).get()); @@ -191,7 +190,7 @@ public void configureRun(RunImpl run) { } } - protected Map buildRunInterpolationData() { + protected Map buildRunInterpolationData(RunImpl run) { final Map interpolationData = Maps.newHashMap(); interpolationData.put("runtime_name", specification.getVersionedName()); diff --git a/common/src/main/java/net/neoforged/gradle/common/util/run/RunsUtil.java b/common/src/main/java/net/neoforged/gradle/common/util/run/RunsUtil.java index e42ed9ae6..6b74f3419 100644 --- a/common/src/main/java/net/neoforged/gradle/common/util/run/RunsUtil.java +++ b/common/src/main/java/net/neoforged/gradle/common/util/run/RunsUtil.java @@ -29,6 +29,14 @@ private RunsUtil() { throw new IllegalStateException("Tried to create utility class!"); } + public static String createTaskName(final Run run) { + return createTaskName(run.getName()); + } + + public static String createTaskName(final String prefix, final Run run) { + return createTaskName(prefix, run.getName()); + } + public static Run create(final Project project, final String name) { final RunImpl run = project.getObjects().newInstance(RunImpl.class, project, name); @@ -112,11 +120,15 @@ public static Provider buildGradleModClasses(final ListProperty { * @return The run dependency. */ RunDependency project(Map notation); + + /** + * Creates a new run dependency from the given configuration notation. + * + * @param notation The configuration to use. + * @return The run dependency. + */ + RunDependency configuration(Configuration notation); } \ No newline at end of file diff --git a/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/definition/NeoFormRuntimeDefinition.java b/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/definition/NeoFormRuntimeDefinition.java index dfb807fff..a84a0961a 100644 --- a/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/definition/NeoFormRuntimeDefinition.java +++ b/neoform/src/main/java/net/neoforged/gradle/neoform/runtime/definition/NeoFormRuntimeDefinition.java @@ -110,8 +110,8 @@ public void configureRun(RunImpl run) { } @Override - public Map buildRunInterpolationData() { - final Map interpolationData = new HashMap<>(super.buildRunInterpolationData()); + public Map buildRunInterpolationData(RunImpl run) { + final Map interpolationData = new HashMap<>(super.buildRunInterpolationData(run)); interpolationData.put("mcp_version", neoform.getVersion()); interpolationData.put("mcp_mappings", new File(unpackedneoformZipDirectory, "config/joined.srg").getAbsolutePath()); diff --git a/platform/src/main/java/net/neoforged/gradle/platform/extensions/DynamicProjectExtension.java b/platform/src/main/java/net/neoforged/gradle/platform/extensions/DynamicProjectExtension.java index febd20827..d0b4b4932 100644 --- a/platform/src/main/java/net/neoforged/gradle/platform/extensions/DynamicProjectExtension.java +++ b/platform/src/main/java/net/neoforged/gradle/platform/extensions/DynamicProjectExtension.java @@ -363,7 +363,7 @@ public void runtime(final String neoFormVersion, Directory patches, Directory re profile.processor(project, processor -> { processor.server(); processor.getJar().set("net.minecraftforge:installertools:1.3.0"); - processor.arguments("--task", "EXTRACT_FILES", "--archive", "{INSTALLER}", + processor.getArguments().addAll("--task", "EXTRACT_FILES", "--archive", "{INSTALLER}", "--from", "data/run.sh", "--to", "{ROOT}/run.sh", "--exec", "{ROOT}/run.sh", @@ -378,42 +378,42 @@ public void runtime(final String neoFormVersion, Directory patches, Directory re profile.processor(project, processor -> { processor.server(); processor.getJar().set("net.minecraftforge:installertools:1.3.0"); - processor.arguments("--task", "BUNDLER_EXTRACT", "--input", "{MINECRAFT_JAR}", "--output", "{ROOT}/libraries/", "--libraries"); + processor.getArguments().addAll("--task", "BUNDLER_EXTRACT", "--input", "{MINECRAFT_JAR}", "--output", "{ROOT}/libraries/", "--libraries"); }); profile.processor(project, processor -> { processor.server(); processor.getJar().set("net.minecraftforge:installertools:1.3.0"); - processor.arguments("--task", "BUNDLER_EXTRACT", "--input", "{MINECRAFT_JAR}", "--output", "{MC_UNPACKED}", "--jar-only"); + processor.getArguments().addAll("--task", "BUNDLER_EXTRACT", "--input", "{MINECRAFT_JAR}", "--output", "{MC_UNPACKED}", "--jar-only"); }); profile.processor(project, processor -> { processor.getJar().set("net.minecraftforge:installertools:1.3.0"); - processor.arguments("--task", "MCP_DATA", "--input", String.format("[%s]", runtimeDefinition.getJoinedNeoFormRuntimeDefinition().getSpecification().getNeoFormArtifact().toString()), "--output", "{MAPPINGS}", "--key", "mappings"); + processor.getArguments().addAll("--task", "MCP_DATA", "--input", String.format("[%s]", runtimeDefinition.getJoinedNeoFormRuntimeDefinition().getSpecification().getNeoFormArtifact().toString()), "--output", "{MAPPINGS}", "--key", "mappings"); }); profile.processor(project, processor -> { processor.getJar().set("net.minecraftforge:installertools:1.3.0"); - processor.arguments("--task", "DOWNLOAD_MOJMAPS", "--version", runtimeDefinition.getSpecification().getMinecraftVersion(), "--side", "{SIDE}", "--output", "{MOJMAPS}"); + processor.getArguments().addAll("--task", "DOWNLOAD_MOJMAPS", "--version", runtimeDefinition.getSpecification().getMinecraftVersion(), "--side", "{SIDE}", "--output", "{MOJMAPS}"); }); profile.processor(project, processor -> { processor.getJar().set("net.minecraftforge:installertools:1.3.0"); - processor.arguments("--task", "MERGE_MAPPING", "--left", "{MAPPINGS}", "--right", "{MOJMAPS}", "--output", "{MERGED_MAPPINGS}", "--classes", "--fields", "--methods", "--reverse-right"); + processor.getArguments().addAll("--task", "MERGE_MAPPING", "--left", "{MAPPINGS}", "--right", "{MOJMAPS}", "--output", "{MERGED_MAPPINGS}", "--classes", "--fields", "--methods", "--reverse-right"); }); profile.processor(project, processor -> { processor.client(); processor.getJar().set("net.minecraftforge:jarsplitter:1.1.4"); - processor.arguments("--input", "{MINECRAFT_JAR}", "--slim", "{MC_SLIM}", "--extra", "{MC_EXTRA}", "--srg", "{MERGED_MAPPINGS}"); + processor.getArguments().addAll("--input", "{MINECRAFT_JAR}", "--slim", "{MC_SLIM}", "--extra", "{MC_EXTRA}", "--srg", "{MERGED_MAPPINGS}"); }); profile.processor(project, processor -> { processor.server(); processor.getJar().set("net.minecraftforge:jarsplitter:1.1.4"); - processor.arguments("--input", "{MC_UNPACKED}", "--slim", "{MC_SLIM}", "--extra", "{MC_EXTRA}", "--srg", "{MERGED_MAPPINGS}"); + processor.getArguments().addAll("--input", "{MC_UNPACKED}", "--slim", "{MC_SLIM}", "--extra", "{MC_EXTRA}", "--srg", "{MERGED_MAPPINGS}"); }); profile.processor(project, processor -> { processor.getJar().set(Constants.FART); - processor.arguments("--input", "{MC_SLIM}", "--output", "{MC_SRG}", "--names", "{MERGED_MAPPINGS}", "--ann-fix", "--ids-fix", "--src-fix", "--record-fix"); + processor.getArguments().addAll("--input", "{MC_SLIM}", "--output", "{MC_SRG}", "--names", "{MERGED_MAPPINGS}", "--ann-fix", "--ids-fix", "--src-fix", "--record-fix"); }); profile.processor(project, processor -> { processor.getJar().set("net.minecraftforge:binarypatcher:1.1.1"); - processor.arguments("--clean", "{MC_SRG}", "--output", "{PATCHED}", "--apply", "{BINPATCH}"); + processor.getArguments().addAll("--clean", "{MC_SRG}", "--output", "{PATCHED}", "--apply", "{BINPATCH}"); }); profile.getLibraries().add(Library.fromOutput(signUniversalJar, project, "net.neoforged", "neoforge", project.getVersion().toString(), "universal")); diff --git a/platform/src/main/java/net/neoforged/gradle/platform/runtime/runtime/definition/RuntimeDevRuntimeDefinition.java b/platform/src/main/java/net/neoforged/gradle/platform/runtime/runtime/definition/RuntimeDevRuntimeDefinition.java index 6afca5e57..2f6f46384 100644 --- a/platform/src/main/java/net/neoforged/gradle/platform/runtime/runtime/definition/RuntimeDevRuntimeDefinition.java +++ b/platform/src/main/java/net/neoforged/gradle/platform/runtime/runtime/definition/RuntimeDevRuntimeDefinition.java @@ -71,8 +71,8 @@ public TaskProvider getListLibrariesTaskProvider() { } @Override - protected Map buildRunInterpolationData() { - final Map interpolationData = joinedNeoFormRuntimeDefinition.buildRunInterpolationData(); + protected Map buildRunInterpolationData(RunImpl run) { + final Map interpolationData = joinedNeoFormRuntimeDefinition.buildRunInterpolationData(run); return interpolationData; } diff --git a/userdev/src/main/java/net/neoforged/gradle/userdev/runtime/definition/UserDevRuntimeDefinition.java b/userdev/src/main/java/net/neoforged/gradle/userdev/runtime/definition/UserDevRuntimeDefinition.java index a2e3e572d..800b89286 100644 --- a/userdev/src/main/java/net/neoforged/gradle/userdev/runtime/definition/UserDevRuntimeDefinition.java +++ b/userdev/src/main/java/net/neoforged/gradle/userdev/runtime/definition/UserDevRuntimeDefinition.java @@ -7,9 +7,11 @@ import net.neoforged.gradle.common.runtime.tasks.DownloadAssets; import net.neoforged.gradle.common.runtime.tasks.ExtractNatives; import net.neoforged.gradle.common.util.VersionJson; +import net.neoforged.gradle.common.util.run.RunsUtil; import net.neoforged.gradle.dsl.common.runtime.definition.Definition; import net.neoforged.gradle.dsl.common.tasks.WithOutput; import net.neoforged.gradle.dsl.common.util.CommonRuntimeUtils; +import net.neoforged.gradle.dsl.common.util.ConfigurationUtils; import net.neoforged.gradle.dsl.userdev.configurations.UserdevProfile; import net.neoforged.gradle.dsl.userdev.runtime.definition.UserDevDefinition; import net.neoforged.gradle.neoform.runtime.definition.NeoFormRuntimeDefinition; @@ -21,6 +23,8 @@ import org.jetbrains.annotations.NotNull; import java.io.File; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -32,7 +36,9 @@ public final class UserDevRuntimeDefinition extends CommonRuntimeDefinition minecraftClasspathSerializer; + + private final List> classpathSerializers = new ArrayList<>(); + private TaskProvider repoWritingTask = null; public UserDevRuntimeDefinition(@NotNull UserDevRuntimeSpecification specification, NeoFormRuntimeDefinition neoformRuntimeDefinition, File unpackedUserDevJarDirectory, UserdevProfile userdevConfiguration, Configuration additionalUserDevDependencies) { super(specification, neoformRuntimeDefinition.getTasks(), neoformRuntimeDefinition.getSourceJarTask(), neoformRuntimeDefinition.getRawJarTask(), neoformRuntimeDefinition.getGameArtifactProvidingTasks(), neoformRuntimeDefinition.getMinecraftDependenciesConfiguration(), neoformRuntimeDefinition::configureAssociatedTask, neoformRuntimeDefinition.getVersionJson()); @@ -46,17 +52,6 @@ public UserDevRuntimeDefinition(@NotNull UserDevRuntimeSpecification specificati ExtraJarDependencyManager.generateClientCoordinateFor(this.getSpecification().getMinecraftVersion()) ) ); - - this.minecraftClasspathSerializer = specification.getProject().getTasks().register( - CommonRuntimeUtils.buildStepName(getSpecification(), "writeMinecraftClasspath"), - ClasspathSerializer.class, - task -> { - this.additionalUserDevDependencies.getExtendsFrom().forEach(task.getInputFiles()::from); - task.getInputFiles().from(this.additionalUserDevDependencies); - task.getInputFiles().from(neoformRuntimeDefinition.getMinecraftDependenciesConfiguration()); - } - ); - configureAssociatedTask(this.minecraftClasspathSerializer); } @Override @@ -89,9 +84,12 @@ public void setReplacedDependency(@NotNull Dependency dependency) { @Override public void onRepoWritten(@NotNull final TaskProvider finalRepoWritingTask) { neoformRuntimeDefinition.onRepoWritten(finalRepoWritingTask); - this.minecraftClasspathSerializer.configure(task -> { + + classpathSerializers.forEach(taskProvider -> taskProvider.configure(task -> { task.getInputFiles().from(finalRepoWritingTask); - }); + })); + classpathSerializers.clear(); + this.repoWritingTask = finalRepoWritingTask; } @Override @@ -108,27 +106,16 @@ public void onRepoWritten(@NotNull final TaskProvider fina public @NotNull Map getMappingVersionData() { return neoformRuntimeDefinition.getMappingVersionData(); } - - @Override - public void configureRun(RunImpl run) { - super.configureRun(run); - run.dependsOn(this.minecraftClasspathSerializer); - } - + @NotNull @Override public TaskProvider getListLibrariesTaskProvider() { return neoformRuntimeDefinition.getListLibrariesTaskProvider(); } - @NotNull - public TaskProvider getMinecraftClasspathSerializer() { - return minecraftClasspathSerializer; - } - @Override - protected Map buildRunInterpolationData() { - final Map interpolationData = neoformRuntimeDefinition.buildRunInterpolationData(); + protected Map buildRunInterpolationData(RunImpl run) { + final Map interpolationData = neoformRuntimeDefinition.buildRunInterpolationData(run); if (userdevConfiguration.getModules() != null && !userdevConfiguration.getModules().get().isEmpty()) { final String name = String.format("moduleResolverForgeUserDev%s", getSpecification().getVersionedName()); @@ -144,9 +131,32 @@ protected Map buildRunInterpolationData() { interpolationData.put("modules", modulesCfg.resolve().stream().map(File::getAbsolutePath).collect(Collectors.joining(File.pathSeparator))); } + + final TaskProvider minecraftClasspathSerializer = getSpecification().getProject().getTasks().register( + RunsUtil.createTaskName("writeMinecraftClasspath", run), + ClasspathSerializer.class, + task -> { + this.additionalUserDevDependencies.getExtendsFrom().forEach(task.getInputFiles()::from); + task.getInputFiles().from(this.additionalUserDevDependencies); + task.getInputFiles().from(neoformRuntimeDefinition.getMinecraftDependenciesConfiguration()); - interpolationData.put("minecraft_classpath_file", this.minecraftClasspathSerializer.get().getOutput().get().getAsFile().getAbsolutePath()); - + run.getDependencies().get().getRuntime().get().forEach(runDependency -> task.getInputFiles().from(runDependency.getDependency())); + } + ); + configureAssociatedTask(minecraftClasspathSerializer); + + interpolationData.put("minecraft_classpath_file", minecraftClasspathSerializer.get().getOutput().get().getAsFile().getAbsolutePath()); + + run.dependsOn(minecraftClasspathSerializer); + + if (repoWritingTask == null) { + classpathSerializers.add(minecraftClasspathSerializer); + } else { + minecraftClasspathSerializer.configure(task -> { + task.getInputFiles().from(repoWritingTask); + }); + } + return interpolationData; } diff --git a/vanilla/src/main/java/net/neoforged/gradle/vanilla/runtime/VanillaRuntimeDefinition.java b/vanilla/src/main/java/net/neoforged/gradle/vanilla/runtime/VanillaRuntimeDefinition.java index 98db6b778..07b0b6238 100644 --- a/vanilla/src/main/java/net/neoforged/gradle/vanilla/runtime/VanillaRuntimeDefinition.java +++ b/vanilla/src/main/java/net/neoforged/gradle/vanilla/runtime/VanillaRuntimeDefinition.java @@ -73,7 +73,7 @@ public Optional getServerLaunchInformation() { } @Override - protected Map buildRunInterpolationData() { + protected Map buildRunInterpolationData(RunImpl run) { final Map interpolationData = Maps.newHashMap(); final String fgVersion = this.getClass().getPackage().getImplementationVersion(); @@ -100,7 +100,7 @@ public void configureRun(RunImpl run) { run.getIsClient().set(true); run.getIsSingleInstance().set(false); - final Map interpolationData = Maps.newHashMap(buildRunInterpolationData()); + final Map interpolationData = Maps.newHashMap(buildRunInterpolationData(run)); interpolationData.put(InterpolationConstants.GAME_DIRECTORY, run.getWorkingDirectory().get().getAsFile().getAbsolutePath()); run.overrideJvmArguments(interpolate(run.getJvmArguments(), interpolationData, "$"));