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.File; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
|  | import java.io.StringReader; | ||||||
|  | import java.io.StringWriter; | ||||||
| import java.nio.charset.StandardCharsets; | import java.nio.charset.StandardCharsets; | ||||||
|  | import java.nio.file.Files; | ||||||
|  | import java.nio.file.Path; | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| import java.util.LinkedList; | import java.util.LinkedList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| 
 | 
 | ||||||
| import javax.inject.Inject; | 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.apache.commons.io.FileUtils; | ||||||
| import org.gradle.api.Project; | import org.gradle.api.Project; | ||||||
| import org.gradle.api.tasks.TaskAction; | 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.LoomGradleExtension; | ||||||
| import net.fabricmc.loom.configuration.ide.RunConfig; | import net.fabricmc.loom.configuration.ide.RunConfig; | ||||||
|  | @ -95,7 +111,7 @@ public abstract class IdeaSyncTask extends AbstractLoomTask { | ||||||
| 
 | 
 | ||||||
| 			if (settings.getEnvironment().equals("server") && !excludedServerLibraries.isEmpty()) { | 			if (settings.getEnvironment().equals("server") && !excludedServerLibraries.isEmpty()) { | ||||||
| 				try { | 				try { | ||||||
| 					setClasspathModifications(runConfigs, excludedServerLibraries); | 					setClasspathModifications(runConfigs.toPath(), excludedServerLibraries); | ||||||
| 				} catch (Exception e) { | 				} catch (Exception e) { | ||||||
| 					getProject().getLogger().error("Failed to modify run configuration xml", e); | 					getProject().getLogger().error("Failed to modify run configuration xml", e); | ||||||
| 				} | 				} | ||||||
|  | @ -124,7 +140,67 @@ public abstract class IdeaSyncTask extends AbstractLoomTask { | ||||||
| 		return clientOnlyLibraries; | 		return clientOnlyLibraries; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private void setClasspathModifications(File runConfig, List<String> exclusions) throws Exception { | 	private void setClasspathModifications(Path runConfig, List<String> exclusions) throws IOException { | ||||||
| 		// TODO modify the xml | 		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