Support putting run configs in folders (#1276)

* Remove unused RunConfig.genRuns

* Support putting run configs in folders

* Fix checkstyle complaints

Given how many of my projects use checkstyle, you'd have thought I'd
remember to check it before submitting a PR.

* Fix IdeaClasspathModificationsTest

"I won't run the tests, I've tested manually, and nothing will break".
Words spoken before disaster (or at least making a fool of myself in
CI).
This commit is contained in:
Jonathan Coates
2025-04-07 11:55:15 +01:00
committed by GitHub
parent 24fdf5af5c
commit d463501e9b
4 changed files with 32 additions and 52 deletions

View File

@@ -38,11 +38,12 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import groovy.xml.XmlUtil;
import org.gradle.api.JavaVersion;
import org.gradle.api.Project;
import org.gradle.api.artifacts.ModuleVersionIdentifier;
@@ -50,9 +51,6 @@ import org.gradle.api.artifacts.ResolvedArtifact;
import org.gradle.api.artifacts.ResolvedModuleVersion;
import org.gradle.api.tasks.SourceSet;
import org.gradle.plugins.ide.eclipse.model.EclipseModel;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.configuration.InstallerData;
@@ -64,6 +62,8 @@ import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.gradle.SourceSetReference;
public class RunConfig {
private static final Pattern VARIABLE = Pattern.compile("%[A-Z_]+%");
public String configName;
public String eclipseProjectName;
public String ideaModuleName;
@@ -76,42 +76,7 @@ public class RunConfig {
public transient SourceSet sourceSet;
public Map<String, Object> environmentVariables;
public String projectName;
public Element genRuns(Element doc) {
Element root = this.addXml(doc, "component", ImmutableMap.of("name", "ProjectRunConfigurationManager"));
root = addXml(root, "configuration", ImmutableMap.of("default", "false", "name", configName, "type", "Application", "factoryName", "Application"));
this.addXml(root, "module", ImmutableMap.of("name", ideaModuleName));
this.addXml(root, "option", ImmutableMap.of("name", "MAIN_CLASS_NAME", "value", mainClass));
this.addXml(root, "option", ImmutableMap.of("name", "WORKING_DIRECTORY", "value", runDirIdeaUrl));
if (!vmArgs.isEmpty()) {
this.addXml(root, "option", ImmutableMap.of("name", "VM_PARAMETERS", "value", joinArguments(vmArgs)));
}
if (!programArgs.isEmpty()) {
this.addXml(root, "option", ImmutableMap.of("name", "PROGRAM_PARAMETERS", "value", joinArguments(programArgs)));
}
return root;
}
public Element addXml(Node parent, String name, Map<String, String> values) {
Document doc = parent.getOwnerDocument();
if (doc == null) {
doc = (Document) parent;
}
Element e = doc.createElement(name);
for (Map.Entry<String, String> entry : values.entrySet()) {
e.setAttribute(entry.getKey(), entry.getValue());
}
parent.appendChild(e);
return e;
}
public String folderName;
// Turns camelCase/PascalCase into Capital Case
// caseConversionExample -> Case Conversion Example
@@ -191,6 +156,7 @@ public class RunConfig {
runConfig.environmentVariables = new HashMap<>();
runConfig.environmentVariables.putAll(settings.getEnvironmentVariables());
runConfig.projectName = project.getName();
runConfig.folderName = settings.getIdeConfigFolder().getOrNull();
return runConfig;
}
@@ -212,17 +178,20 @@ public class RunConfig {
runDir = relativePath + "/" + runDir;
}
dummyConfig = dummyConfig.replace("%NAME%", configName);
dummyConfig = dummyConfig.replace("%MAIN_CLASS%", mainClass);
dummyConfig = dummyConfig.replace("%ECLIPSE_PROJECT%", eclipseProjectName);
dummyConfig = dummyConfig.replace("%IDEA_MODULE%", ideaModuleName);
dummyConfig = dummyConfig.replace("%RUN_DIRECTORY%", runDir);
dummyConfig = dummyConfig.replace("%PROGRAM_ARGS%", joinArguments(programArgs).replaceAll("\"", "&quot;"));
dummyConfig = dummyConfig.replace("%VM_ARGS%", joinArguments(vmArgs).replaceAll("\"", "&quot;"));
dummyConfig = dummyConfig.replace("%IDEA_ENV_VARS%", getEnvVars("<env name=\"%s\" value=\"%s\"/>"));
dummyConfig = dummyConfig.replace("%ECLIPSE_ENV_VARS%", getEnvVars("<mapEntry key=\"%s\" value=\"%s\"/>"));
var replacements = Map.of(
"%NAME%", configName,
"%MAIN_CLASS%", mainClass,
"%ECLIPSE_PROJECT%", eclipseProjectName,
"%IDEA_MODULE%", ideaModuleName,
"%RUN_DIRECTORY%", runDir,
"%PROGRAM_ARGS%", joinArguments(programArgs).replaceAll("\"", "&quot;"),
"%VM_ARGS%", joinArguments(vmArgs).replaceAll("\"", "&quot;"),
"%IDEA_ENV_VARS%", getEnvVars("<env name=\"%s\" value=\"%s\"/>"),
"%ECLIPSE_ENV_VARS%", getEnvVars("<mapEntry key=\"%s\" value=\"%s\"/>"),
"%IDEA_FOLDER_NAME%", folderName == null ? "" : "folderName=\"" + XmlUtil.escapeXml(folderName) + "\""
);
return dummyConfig;
return VARIABLE.matcher(dummyConfig).replaceAll(x -> replacements.getOrDefault(x.group(), ""));
}
private String getEnvVars(String pattern) {

View File

@@ -48,7 +48,7 @@ import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.Platform;
import net.fabricmc.loom.util.gradle.SourceSetHelper;
public class RunConfigSettings implements Named {
public abstract class RunConfigSettings implements Named {
/**
* Arguments for the JVM, such as system properties.
*/
@@ -362,6 +362,7 @@ public class RunConfigSettings implements Named {
defaultMainClass = parent.defaultMainClass;
source = parent.source;
ideConfigGenerated = parent.ideConfigGenerated;
getIdeConfigFolder().set(parent.getIdeConfigFolder());
}
public void makeRunDir() {
@@ -380,6 +381,15 @@ public class RunConfigSettings implements Named {
this.ideConfigGenerated = ideConfigGenerated;
}
/**
* Group this run config under the given folder.
*
* <p>This is currently only supported on IntelliJ IDEA.
*
* @return The property used to set the config folder.
*/
public abstract Property<String> getIdeConfigFolder();
@ApiStatus.Internal
@ApiStatus.Experimental
public Property<String> devLaunchMainClass() {

View File

@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="%NAME%" type="Application" factoryName="Application">
<configuration default="false" name="%NAME%" type="Application" factoryName="Application" %IDEA_FOLDER_NAME%>
<option name="MAIN_CLASS_NAME" value="%MAIN_CLASS%" />
<module name="%IDEA_MODULE%" />
<option name="PROGRAM_PARAMETERS" value="%PROGRAM_ARGS%" />

View File

@@ -69,6 +69,7 @@ class IdeaClasspathModificationsTest extends Specification {
dummyConfig = dummyConfig.replace("%RUN_DIRECTORY%", ".run")
dummyConfig = dummyConfig.replace("%PROGRAM_ARGS%", RunConfig.joinArguments([]).replaceAll("\"", "&quot;"))
dummyConfig = dummyConfig.replace("%VM_ARGS%", RunConfig.joinArguments([]).replaceAll("\"", "&quot;"))
dummyConfig = dummyConfig.replace("%IDEA_FOLDER_NAME%", "")
return dummyConfig
}