Skip to content

Commit

Permalink
Merge pull request #52 from modelix/MODELIX-813-add-options-to-specif…
Browse files Browse the repository at this point in the history
…y-mps-plugins-for-run-configuration

feat: add options to specify MPS plugins for run configuration
  • Loading branch information
slisson authored Jul 18, 2024
2 parents 4184289 + dce6cb7 commit 41415a4
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.setValue
import org.modelix.buildtools.Macros
import org.modelix.buildtools.readXmlFile
import org.modelix.buildtools.runner.BundledPluginPath
import org.modelix.buildtools.runner.ExternalPluginPath
import org.modelix.buildtools.runner.MPSRunnerConfig
import org.modelix.buildtools.runner.PluginConfig
import org.w3c.dom.Document
import java.io.File
import java.net.URL
Expand Down Expand Up @@ -279,5 +282,8 @@ open class MPSBuildSettings(val project: Project) {
fun jarLibrary(file: File) = updateConfig { it.copy(classPathElements = it.classPathElements + file) }
fun jarLibraries(dir: File) = updateConfig { it.copy(jarFolders = it.classPathElements + dir) }
fun jvmArg(arg: String) = updateConfig { it.copy(jvmArgs = it.jvmArgs + arg) }
fun bundledPlugin(id: String, dir: File) = updateConfig { it.copy(plugins = it.plugins + PluginConfig(id, BundledPluginPath(dir))) }
fun externalPlugin(id: String, dir: File) = updateConfig { it.copy(plugins = it.plugins + PluginConfig(id, ExternalPluginPath(dir))) }
fun autoPluginDiscovery(autoPluginDiscovery: Boolean?) = updateConfig { it.copy(autoPluginDiscovery = autoPluginDiscovery) }
}
}
1 change: 1 addition & 0 deletions build-tools-lib/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ dependencies {
implementation(libs.apache.commons.text)
implementation(libs.apache.commons.io)
testImplementation(libs.junit.jupiter.api)
testImplementation(libs.assertj)
testRuntimeOnly(libs.junit.jupiter.engine)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class MPSRunner(
originalConfig: MPSRunnerConfig,
) {
companion object {
internal const val PROPERTY_KEY_ARTIFACTS_MPS = "artifacts.mps"

// https://github.com/mbeddr/mps-build-backends/blob/b62bc815cf79d2c4af16ae38c2b0d98701c8f1db/launcher/src/main/java/de/itemis/mps/gradle/launcher/MpsBackendBuilder.java#L115
private val jvmOpens = listOf(
"java.base/java.io",
Expand Down Expand Up @@ -95,7 +97,7 @@ class MPSRunner(
fun generateAll() {
processConfig()
generateSolution()
generateAntScript()
generateAntScriptFile()
}

private fun getMpsBuildPropertiesFile() = config.mpsHome!!.resolve("build.properties")
Expand Down Expand Up @@ -172,11 +174,9 @@ class MPSRunner(
getSolutionFile().writeText(xml)
}

private fun generateAntScript() {
val mpsVersion = getMpsVersion()
val antScriptFile = getAntScriptFile()
fun generateAntScriptText(mpsVersion: String): String {
val antLibs = BuildScriptGenerator.getMpsAntLibraries(mpsVersion)
val xml = buildXmlString {
return buildXmlString {
newChild("project") {
setAttribute("name", getFileNamePrefix())
setAttribute("default", RUN_MPS_TASK_NAME)
Expand All @@ -198,7 +198,7 @@ class MPSRunner(
setAttribute("location", config.mpsHome!!.absolutePath)
}
newChild("property") {
setAttribute("name", "artifacts.mps")
setAttribute("name", PROPERTY_KEY_ARTIFACTS_MPS)
setAttribute("location", "\${mps.home}")
}
newChild("property") {
Expand Down Expand Up @@ -237,6 +237,22 @@ class MPSRunner(
setAttribute("solution", "${config.moduleId}(${getSolutionName()})")
setAttribute("startClass", config.mainClassName)
setAttribute("startMethod", config.mainMethodName)
if (config.autoPluginDiscovery != null) {
setAttribute("autoPluginDiscovery", config.autoPluginDiscovery.toString())
}

for (plugin in config.plugins) {
newChild("plugin") {
val pathXmlValue = when (plugin.path) {
// We can use the forward slash as path separator for Windows,
// because MPS also use it when generating for Windows.
is BundledPluginPath -> "\${$PROPERTY_KEY_ARTIFACTS_MPS}/${plugin.path.dir}"
is ExternalPluginPath -> plugin.path.dir.absolutePath
}
setAttribute("path", pathXmlValue)
setAttribute("id", plugin.id)
}
}

newChild("library") { setAttribute("file", getMpsLanguagesDir().absolutePath) }
newChild("library") { setAttribute("file", getSolutionDir().absolutePath) }
Expand All @@ -256,8 +272,13 @@ class MPSRunner(
}
}
}
}

private fun generateAntScriptFile() {
val mpsVersion = getMpsVersion()
val antScriptText = generateAntScriptText(mpsVersion)
val antScriptFile = getAntScriptFile()
antScriptFile.parentFile.mkdirs()
antScriptFile.writeText(xml)
antScriptFile.writeText(antScriptText)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,41 @@ data class MPSRunnerConfig(
val buildDir: File? = null,
val jvmArgs: List<String> = emptyList(),
val moduleId: UUID? = null,
val plugins: List<PluginConfig> = emptyList(),
/**
* Enable or disable automatically loading available plugins.
* If a value is specified, it will be set as the
* "autoPluginDiscovery" property [jetbrains.mps.build.ant.MpsLoadTask.setAutoPluginDiscovery]
* on the "runMPS" task [jetbrains.mps.build.ant.generation.MpsRunnerTask].
*/
val autoPluginDiscovery: Boolean? = null,
) : Serializable {
fun buildDir() = buildDir ?: workDir()
fun workDir() = workDir ?: File(".")
}

/**
* Specifies a plugin by its [id] and the [path] of its installation.
*/
data class PluginConfig(val id: String, val path: PluginPath) : Serializable

sealed interface PluginPath : Serializable

/**
* A path to an external plugin directory.
*/
data class ExternalPluginPath(val dir: File) : PluginPath

/**
* A path to a bundled plugin directory.
* [dir] has to be a relative path.
* When the build script is executed it will be resolved against the path
* specified by the value of the property [MPSRunner.PROPERTY_KEY_ARTIFACTS_MPS].
*/
data class BundledPluginPath(val dir: File) : PluginPath {
init {
require(!dir.isAbsolute) {
"The path `$dir` to a bundled plugin must be a relative path."
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.modelix.buildtools.runner

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import java.io.File

class MPSRunnerTest {
val mpsVersion = "2023.3.1"
val buildDir = File("/buildDir")
val mpsHome = File("/mpsHome")

@Test
fun `generate config with bundled plugins`() {
val plugins = listOf(PluginConfig("aPluginId", BundledPluginPath(File("plugins/aPluginFolder"))))
val config = MPSRunnerConfig(buildDir = buildDir, mpsHome = mpsHome, plugins = plugins)
val runner = MPSRunner(config)

val antScriptText = runner.generateAntScriptText(mpsVersion)

assertThat(antScriptText)
.contains("""<plugin id="aPluginId" path="${'$'}{artifacts.mps}/plugins/aPluginFolder"/>""")
}

@Test
fun `bundled plugin cannot be created with an absolute path`() {
val exception = assertThrows<IllegalArgumentException> {
BundledPluginPath(File("/plugins/aPluginFolder"))
}

assertThat(exception)
.hasMessage("The path `/plugins/aPluginFolder` to a bundled plugin must be a relative path.")
}

@Test
fun `generate config with external plugins`() {
val plugins = listOf(PluginConfig("aPluginId", ExternalPluginPath(File("/aPluginFolder"))))
val config = MPSRunnerConfig(buildDir = buildDir, mpsHome = mpsHome, plugins = plugins)
val runner = MPSRunner(config)

val antScriptText = runner.generateAntScriptText(mpsVersion)

assertThat(antScriptText)
.contains("""<plugin id="aPluginId" path="/aPluginFolder"/>""")
}

@Test
fun `generate config with enabled autoPluginDiscovery`() {
val config = MPSRunnerConfig(buildDir = buildDir, mpsHome = mpsHome, autoPluginDiscovery = true)
val runner = MPSRunner(config)

val antScriptText = runner.generateAntScriptText(mpsVersion)

assertThat(antScriptText)
.contains("""<runMPS autoPluginDiscovery="true" solution="null(runMPS_null.solution)" startClass="Main" startMethod="main">""")
}
}
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ apache-commons-io = { group = "commons-io", name = "commons-io", version = "2.16
zt-zip = { group = "org.zeroturnaround", name = "zt-zip", version = "1.17" }
junit-jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junitJupiter" }
junit-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junitJupiter" }
assertj = { group = "org.assertj", name = "assertj-core", version = "3.25.1"}

[bundles]

0 comments on commit 41415a4

Please sign in to comment.