MinecraftForge / ForgeGradle

Minecraft mod development framework used by Forge and FML for the gradle build system
GNU Lesser General Public License v2.1
526 stars 447 forks source link

Fix IntelliJ run configurations for multiprojects built with IntelliJ #851

Closed sciwhiz12 closed 2 years ago

sciwhiz12 commented 2 years ago

When generating IntelliJ IDEA run configurations (using the genIntellijRuns command) for a multi-project where the IDEA project is configured to build and test using IntelliJ rather than Gradle and the run configs contain source sets from other subprojects, two issues would occur:

  1. The output folders for the other projects' source sets in the MOD_CLASSES environment folder, derived based on IntelliJ's default settings when building and testing using IntelliJ, would have the wrong parent location. Instead of using the correct directory of the other project to which the source set belongs, the directory used instead is of the same project where ForgeGradle is applied to.

    This is fixed by using a solution similar to the one used in EclipseRunGenerator#mapModClassesToEclipse (added by #828): maintaining a map of source sets to source-set-specific data. In this case, the source-set-specific data stored in the map is the Project which owns the source set. This map is then queried later on for the source set's owning project and used instead of the previous behavior of using the project where ForgeGradle is applied to.

  2. The output folders for the other projects' main source set in the MOD_CLASSES environment folder used the main identifier, rather than the special-cased production identifier[^1]. For example, for a project Boop's main source set, the output folder for classes would (incorrectly) be calculated as $PROJECT_DIR$/Boop/out/main/classes (assuming the above first issue is fixed).

    This is fixed by replacing the instance comparison with checking the source set's name if it equals to main (from the constant SourceSet.MAIN_SOURCE_SET_NAME).

Additionally, #getIdeaPathsForSourceset was modified to use the information from IdeaModule and $MODULE_DIR$ instead of from IdeaProject and $PROJECT_DIR$. This is because of two reasons:

  1. The IdeaProject is only present and non-null on the IdeaModel of the root project. This causes issues when, because of the above changes, a subproject is passed to the method with a present IdeaModel (because of the application of the IDEA plugin previous) but a null IdeaProject, causing a NullPointerException when trying to invoke IdeaProject#getPathFactory.[^2]

  2. $PROJECT_DIR$ resolves to the directory of the root project, which means incorrect calculation of the output folder (because the output folder of a subproject exists under the subproject's directory). Changing to $MODULE_DIR fixes this (in conjunction with the above required change to use IdeaModel), as this properly points to the subproject's directory.[^3]

Finally, some miscellaneous cleanup was performed on IntellijRunGenerator to remove cruft and resolve warnings.

[^1]: By default, IntelliJ IDEA (when configured to build the project instead of Gradle) outputs the classes and resources of the main source set to out/production, and the classes and resources of the test source set to out/test. [^2]: A NullPointerException never occurred previously here because neither ForgeGradle nor IntelliJ IDEA (at least, in my investigations) applied the IDEA plugin to the subproject. This meant that IdeaModel would be null, and therefore the (null) IdeaProject would not be queried or invoked. [^3]: It should be noted that there is a difference in terminology between IntelliJ and Gradle which should be noted for this: an IntelliJ project is better mapped as the whole Gradle build (or root project at least), while an IntelliJ module is better mapped as a single Gradle project (whether the root project or a subproject thereof).

SizableShrimp commented 2 years ago

don't break kthxbye :shipit: