Exclude client only libraries in the IntelliJ server run config.
This commit is contained in:
		
							parent
							
								
									87abd7ad7b
								
							
						
					
					
						commit
						15afb45769
					
				
					 2 changed files with 183 additions and 3 deletions
				
			
		|  | @ -26,17 +26,33 @@ package net.fabricmc.loom.configuration.ide.idea; | |||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.io.StringReader; | ||||
| import java.io.StringWriter; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.nio.file.Files; | ||||
| import java.nio.file.Path; | ||||
| import java.util.Collections; | ||||
| import java.util.LinkedList; | ||||
| import java.util.List; | ||||
| import java.util.Set; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
| import javax.xml.parsers.DocumentBuilder; | ||||
| import javax.xml.parsers.DocumentBuilderFactory; | ||||
| import javax.xml.transform.OutputKeys; | ||||
| import javax.xml.transform.Transformer; | ||||
| import javax.xml.transform.TransformerFactory; | ||||
| import javax.xml.transform.dom.DOMSource; | ||||
| import javax.xml.transform.stream.StreamResult; | ||||
| 
 | ||||
| import org.apache.commons.io.FileUtils; | ||||
| import org.gradle.api.Project; | ||||
| import org.gradle.api.tasks.TaskAction; | ||||
| import org.jetbrains.annotations.VisibleForTesting; | ||||
| import org.w3c.dom.Document; | ||||
| import org.w3c.dom.Element; | ||||
| import org.w3c.dom.NodeList; | ||||
| import org.xml.sax.InputSource; | ||||
| 
 | ||||
| import net.fabricmc.loom.LoomGradleExtension; | ||||
| import net.fabricmc.loom.configuration.ide.RunConfig; | ||||
|  | @ -95,7 +111,7 @@ public abstract class IdeaSyncTask extends AbstractLoomTask { | |||
| 
 | ||||
| 			if (settings.getEnvironment().equals("server") && !excludedServerLibraries.isEmpty()) { | ||||
| 				try { | ||||
| 					setClasspathModifications(runConfigs, excludedServerLibraries); | ||||
| 					setClasspathModifications(runConfigs.toPath(), excludedServerLibraries); | ||||
| 				} catch (Exception e) { | ||||
| 					getProject().getLogger().error("Failed to modify run configuration xml", e); | ||||
| 				} | ||||
|  | @ -124,7 +140,67 @@ public abstract class IdeaSyncTask extends AbstractLoomTask { | |||
| 		return clientOnlyLibraries; | ||||
| 	} | ||||
| 
 | ||||
| 	private void setClasspathModifications(File runConfig, List<String> exclusions) throws Exception { | ||||
| 		// TODO modify the xml | ||||
| 	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; | ||||
| 
 | ||||
| 		try { | ||||
| 			outputXml = setClasspathModificationsInXml(inputXml, exclusions); | ||||
| 		} catch (Exception e) { | ||||
| 			getLogger().error("Failed to modify idea xml", e); | ||||
| 
 | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!inputXml.equals(outputXml)) { | ||||
| 			Files.writeString(runConfig, outputXml, StandardCharsets.UTF_8); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	@VisibleForTesting | ||||
| 	public static String setClasspathModificationsInXml(String input, List<String> exclusions) throws Exception { | ||||
| 		final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); | ||||
| 		final DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); | ||||
| 		final Document document = documentBuilder.parse(new InputSource(new StringReader(input))); | ||||
| 		final Element root = document.getDocumentElement(); | ||||
| 
 | ||||
| 		final NodeList nodeList = root.getElementsByTagName("configuration"); | ||||
| 		assert nodeList.getLength() == 1; | ||||
| 
 | ||||
| 		final Element configuration = (Element) nodeList.item(0); | ||||
| 		final NodeList classpathModificationsList = configuration.getElementsByTagName("classpathModifications"); | ||||
| 
 | ||||
| 		// Remove all the existing exclusions | ||||
| 		for (int i = 0; i < classpathModificationsList.getLength(); i++) { | ||||
| 			configuration.removeChild(classpathModificationsList.item(i)); | ||||
| 		} | ||||
| 
 | ||||
| 		final Element classpathModifications = document.createElement("classpathModifications"); | ||||
| 
 | ||||
| 		for (String exclusionPath : exclusions) { | ||||
| 			final Element exclusion = document.createElement("entry"); | ||||
| 
 | ||||
| 			exclusion.setAttribute("exclude", "true"); | ||||
| 			exclusion.setAttribute("path", exclusionPath); | ||||
| 
 | ||||
| 			classpathModifications.appendChild(exclusion); | ||||
| 		} | ||||
| 
 | ||||
| 		configuration.appendChild(classpathModifications); | ||||
| 
 | ||||
| 		final TransformerFactory transformerFactory = TransformerFactory.newInstance(); | ||||
| 		final Transformer transformer = transformerFactory.newTransformer(); | ||||
| 		transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); | ||||
| 
 | ||||
| 		final DOMSource source = new DOMSource(document); | ||||
| 
 | ||||
| 		final StringWriter writer = new StringWriter(); | ||||
| 		transformer.transform(source, new StreamResult(writer)); | ||||
| 
 | ||||
| 		return writer.toString().replace("\r", ""); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,104 @@ | |||
| /* | ||||
|  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||
|  * | ||||
|  * Copyright (c) 2021 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.test.unit | ||||
| 
 | ||||
| import net.fabricmc.loom.configuration.ide.RunConfig | ||||
| import net.fabricmc.loom.configuration.ide.idea.IdeaSyncTask | ||||
| import org.intellij.lang.annotations.Language | ||||
| import spock.lang.Specification | ||||
| 
 | ||||
| import java.nio.charset.StandardCharsets | ||||
| 
 | ||||
| class IdeaClasspathModificationsTest extends Specification { | ||||
| 
 | ||||
|     def "configure exclusions"() { | ||||
|         when: | ||||
|             def input = fromDummy() | ||||
|             def output = IdeaSyncTask.setClasspathModificationsInXml(input, ["/path/to/file.jar"]) | ||||
| 
 | ||||
|         then: | ||||
|             output == EXPECTED | ||||
|     } | ||||
| 
 | ||||
|     def "re-configure exclusions"() { | ||||
|         when: | ||||
|             def input = fromDummy() | ||||
|             def output = IdeaSyncTask.setClasspathModificationsInXml(input, ["/path/to/file.jar"]) | ||||
|             output = IdeaSyncTask.setClasspathModificationsInXml(output, ["/path/to/file.jar", "/path/to/another.jar"]) | ||||
| 
 | ||||
|         then: | ||||
|             output == EXPECTED2 | ||||
|     } | ||||
| 
 | ||||
|     private String fromDummy() { | ||||
|         String dummyConfig | ||||
| 
 | ||||
|         IdeaSyncTask.class.getClassLoader().getResourceAsStream("idea_run_config_template.xml").withCloseable { | ||||
|             dummyConfig = new String(it.readAllBytes(), StandardCharsets.UTF_8) | ||||
|         } | ||||
| 
 | ||||
|         dummyConfig = dummyConfig.replace("%NAME%", "Minecraft Client") | ||||
|         dummyConfig = dummyConfig.replace("%MAIN_CLASS%", "net.minecraft.client.Main") | ||||
|         dummyConfig = dummyConfig.replace("%IDEA_MODULE%", "main.test") | ||||
|         dummyConfig = dummyConfig.replace("%RUN_DIRECTORY%", ".run") | ||||
|         dummyConfig = dummyConfig.replace("%PROGRAM_ARGS%", RunConfig.joinArguments([]).replaceAll("\"", """)) | ||||
|         dummyConfig = dummyConfig.replace("%VM_ARGS%", RunConfig.joinArguments([]).replaceAll("\"", """)) | ||||
| 
 | ||||
|         return dummyConfig | ||||
|     } | ||||
| 
 | ||||
|     @Language("XML") | ||||
|     private static final String EXPECTED = ''' | ||||
| <component name="ProjectRunConfigurationManager"> | ||||
|   <configuration default="false" factoryName="Application" name="Minecraft Client" type="Application"> | ||||
|     <option name="MAIN_CLASS_NAME" value="net.minecraft.client.Main"/> | ||||
|     <module name="main.test"/> | ||||
|     <option name="PROGRAM_PARAMETERS" value=""/> | ||||
|     <option name="VM_PARAMETERS" value=""/> | ||||
|     <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/.run/"/> | ||||
|     <method v="2"> | ||||
|       <option enabled="true" name="Make"/> | ||||
|     </method> | ||||
|   <classpathModifications><entry exclude="true" path="/path/to/file.jar"/></classpathModifications></configuration> | ||||
| </component> | ||||
| '''.trim() | ||||
| 
 | ||||
|     @Language("XML") | ||||
|     private static final String EXPECTED2 = ''' | ||||
| <component name="ProjectRunConfigurationManager"> | ||||
|   <configuration default="false" factoryName="Application" name="Minecraft Client" type="Application"> | ||||
|     <option name="MAIN_CLASS_NAME" value="net.minecraft.client.Main"/> | ||||
|     <module name="main.test"/> | ||||
|     <option name="PROGRAM_PARAMETERS" value=""/> | ||||
|     <option name="VM_PARAMETERS" value=""/> | ||||
|     <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/.run/"/> | ||||
|     <method v="2"> | ||||
|       <option enabled="true" name="Make"/> | ||||
|     </method> | ||||
|   <classpathModifications><entry exclude="true" path="/path/to/file.jar"/><entry exclude="true" path="/path/to/another.jar"/></classpathModifications></configuration> | ||||
| </component> | ||||
| '''.trim() | ||||
| 
 | ||||
| } | ||||
		Loading…
	
		Reference in a new issue