diff --git a/.github/workflows/mps-compatibility.yaml b/.github/workflows/mps-compatibility.yaml new file mode 100644 index 0000000000..d31b3d2db4 --- /dev/null +++ b/.github/workflows/mps-compatibility.yaml @@ -0,0 +1,34 @@ +name: MPS compatibility + +on: + push: + branches: + - 'main' + pull_request: {} + # allow manual execution just in case + workflow_dispatch: + +jobs: + build-mps-components: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '17' + - name: Build with MPS 2020.3.6 + run: ./gradlew :mps-model-adapters:build :mps-model-server-plugin:build -Pmps.version=2020.3.6 + - name: Build with MPS 2021.1.4 + run: ./gradlew :mps-model-adapters:build :mps-model-server-plugin:build -Pmps.version=2021.1.4 + - name: Build with MPS 2021.2.6 + run: ./gradlew :mps-model-adapters:build :mps-model-server-plugin:build -Pmps.version=2021.2.6 + - name: Build with MPS 2021.3.3 + run: ./gradlew :mps-model-adapters:build :mps-model-server-plugin:build -Pmps.version=2021.3.3 + - name: Build with MPS 2022.2 + run: ./gradlew :mps-model-adapters:build :mps-model-server-plugin:build -Pmps.version=2022.2 + - name: Build with MPS 2022.3 + run: ./gradlew :mps-model-adapters:build :mps-model-server-plugin:build -Pmps.version=2022.3 diff --git a/.github/workflows/mps-model-adapters.yaml b/.github/workflows/mps-model-adapters.yaml deleted file mode 100644 index f3ec928e28..0000000000 --- a/.github/workflows/mps-model-adapters.yaml +++ /dev/null @@ -1,34 +0,0 @@ -name: MPS compatibility - -on: - push: - branches: - - 'main' - pull_request: {} - # allow manual execution just in case - workflow_dispatch: - -jobs: - build-mps-model-adapters: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Set up JDK 11 - uses: actions/setup-java@v3 - with: - distribution: 'temurin' - java-version: '11' - - name: Build with MPS 2020.3.6 - run: ./gradlew :mps-model-adapters:build -Pmps.version=2020.3.6 - - name: Build with MPS 2021.1.4 - run: ./gradlew :mps-model-adapters:build -Pmps.version=2021.1.4 - - name: Build with MPS 2021.2.6 - run: ./gradlew :mps-model-adapters:build -Pmps.version=2021.2.6 - - name: Build with MPS 2021.3.3 - run: ./gradlew :mps-model-adapters:build -Pmps.version=2021.3.3 - - name: Build with MPS 2022.2 - run: ./gradlew :mps-model-adapters:build -Pmps.version=2022.2 - - name: Build with MPS 2022.3 - run: ./gradlew :mps-model-adapters:build -Pmps.version=2022.3 diff --git a/build.gradle.kts b/build.gradle.kts index 2210929b01..7d429482fb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,8 +19,11 @@ import kotlinx.html.unsafe import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.DokkaBaseConfiguration import org.jetbrains.dokka.gradle.DokkaTaskPartial +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformJvmPlugin import org.semver.Version buildscript { @@ -63,6 +66,7 @@ dependencies { } subprojects { + val subproject = this apply(plugin = "maven-publish") apply(plugin = "org.jetbrains.dokka") apply(plugin = "org.jlleitschuh.gradle.ktlint") @@ -82,18 +86,42 @@ subprojects { } val kotlinApiVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_6 - tasks.withType().all { + subproject.tasks.withType().configureEach { if (!name.lowercase().contains("test")) { - kotlinOptions { + this.kotlinOptions { jvmTarget = "11" freeCompilerArgs += listOf("-Xjvm-default=all-compatibility") apiVersion = kotlinApiVersion.version } } } + subproject.tasks.withType().configureEach { + if (!name.lowercase().contains("test")) { + this.kotlinOptions { + jvmTarget = "11" + freeCompilerArgs += listOf("-Xjvm-default=all-compatibility") + apiVersion = kotlinApiVersion.version + } + } + } + + subproject.plugins.withType { + subproject.extensions.configure { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + } + + subproject.plugins.withType { + subproject.extensions.configure { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_11) + } + } + } - plugins.withType { - project.extensions.configure { + subproject.plugins.withType { + subproject.extensions.configure { sourceSets.all { if (!name.lowercase().contains("test")) { languageSettings { @@ -104,8 +132,8 @@ subprojects { } } - plugins.withType { - project.extensions.configure { + subproject.plugins.withType { + subproject.extensions.configure { version.set(libs.versions.node) download.set(true) } diff --git a/mps-model-server-plugin/build.gradle.kts b/mps-model-server-plugin/build.gradle.kts index 7e779d6394..693c9e11c2 100644 --- a/mps-model-server-plugin/build.gradle.kts +++ b/mps-model-server-plugin/build.gradle.kts @@ -1,9 +1,27 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { id("org.jetbrains.kotlin.jvm") id("org.jetbrains.intellij") version "1.15.0" } -val mpsVersion = "2021.1.4" +val mpsToIdeaMap = mapOf( + "2020.3.6" to "203.8084.24", // https://github.com/JetBrains/MPS/blob/2020.3.6/build/version.properties + "2021.1.4" to "211.7628.21", // https://github.com/JetBrains/MPS/blob/2021.1.4/build/version.properties + "2021.2.6" to "212.5284.40", // https://github.com/JetBrains/MPS/blob/2021.2.5/build/version.properties (?) + "2021.3.3" to "213.7172.25", // https://github.com/JetBrains/MPS/blob/2021.3.3/build/version.properties + "2022.2" to "222.4554.10", // https://github.com/JetBrains/MPS/blob/2021.2.1/build/version.properties + "2022.3" to "223.8836.41", // https://github.com/JetBrains/MPS/blob/2022.3.0/build/version.properties (?) +) +// use the given MPS version, or 2022.2 (last version with JAVA 11) as default +val mpsVersion = project.findProperty("mps.version")?.toString().takeIf { !it.isNullOrBlank() } ?: "2020.3.6" +if (!mpsToIdeaMap.containsKey(mpsVersion)) { + throw GradleException("Build for the given MPS version '$mpsVersion' is not supported.") +} +// identify the corresponding intelliJ platform version used by the MPS version +val ideaVersion = mpsToIdeaMap.getValue(mpsVersion) +val mpsJavaVersion = if (mpsVersion >= "2022.3") 17 else 11 +println("Building for MPS version $mpsVersion and IntelliJ version $ideaVersion and Java $mpsJavaVersion") dependencies { implementation(project(":model-server-lib")) @@ -19,20 +37,31 @@ dependencies { intellij { // IDEA platform version used in MPS 2021.1.4: https://github.com/JetBrains/MPS/blob/2021.1.4/build/version.properties#L11 - version.set("211.7628.21") + version.set(ideaVersion) // type.set("IC") // Target IDE Platform // plugins.set(listOf("jetbrains.mps.core", "com.intellij.modules.mps")) } +java { + sourceCompatibility = JavaVersion.toVersion(mpsJavaVersion) + targetCompatibility = JavaVersion.toVersion(mpsJavaVersion) +} + +kotlin { + compilerOptions { + jvmTarget.set(JvmTarget.fromTarget(mpsJavaVersion.toString())) + } +} + tasks { withType { - kotlinOptions.jvmTarget = "11" + kotlinOptions.jvmTarget = mpsJavaVersion.toString() } patchPluginXml { - sinceBuild.set("211") + sinceBuild.set("203") untilBuild.set("231.*") } diff --git a/mps-model-server-plugin/src/main/kotlin/org/modelix/model/server/mps/MPSModelServer.kt b/mps-model-server-plugin/src/main/kotlin/org/modelix/model/server/mps/MPSModelServer.kt index aecebeb40a..60a4698c11 100644 --- a/mps-model-server-plugin/src/main/kotlin/org/modelix/model/server/mps/MPSModelServer.kt +++ b/mps-model-server-plugin/src/main/kotlin/org/modelix/model/server/mps/MPSModelServer.kt @@ -13,30 +13,58 @@ */ package org.modelix.model.server.mps -import com.intellij.ide.AppLifecycleListener -import com.intellij.ide.plugins.DynamicPluginListener -import com.intellij.ide.plugins.IdeaPluginDescriptor import com.intellij.openapi.Disposable import com.intellij.openapi.components.Service import com.intellij.openapi.components.service import com.intellij.openapi.project.DumbService import com.intellij.openapi.project.Project +import com.intellij.openapi.startup.StartupActivity import jetbrains.mps.ide.project.ProjectHelper -import jetbrains.mps.project.ProjectBase -import jetbrains.mps.project.ProjectManager -import jetbrains.mps.smodel.MPSModuleRepository +import jetbrains.mps.project.MPSProject import org.modelix.model.api.INode import org.modelix.model.api.runSynchronized import org.modelix.model.mpsadapters.MPSRepositoryAsNode import org.modelix.model.server.light.LightModelServer +import java.util.Collections + +@Service(Service.Level.PROJECT) +class MPSModelServerForProject(private val project: Project) : Disposable { -@Service(Service.Level.APP) -class MPSModelServer : Disposable { init { - println("modelix server created") + service().registerProject(project) } + override fun dispose() { + service().unregisterProject(project) + } +} + +@Service(Service.Level.APP) +class MPSModelServer : Disposable { + private var server: LightModelServer? = null + private val projects: MutableSet = Collections.synchronizedSet(HashSet()) + + fun registerProject(project: Project) { + projects.add(project) + ensureStarted() + } + + fun unregisterProject(project: Project) { + projects.remove(project) + } + + private fun getMPSProjects(): List { + return runSynchronized(projects) { + projects.mapNotNull { it.getComponent(MPSProject::class.java) } + } + } + + private fun getRootNode(): INode? { + return getMPSProjects().asSequence().map { + MPSRepositoryAsNode(it.repository) + }.firstOrNull() + } fun ensureStarted() { runSynchronized(this) { @@ -44,10 +72,9 @@ class MPSModelServer : Disposable { println("starting modelix server") - val rootNodeProvider: () -> INode? = { MPSModuleRepository.getInstance()?.let { MPSRepositoryAsNode(it) } } server = LightModelServer.builder() .port(48305) - .rootNode(rootNodeProvider) + .rootNode(::getRootNode) .healthCheck(object : LightModelServer.IHealthCheck { override val id: String get() = "indexer" @@ -56,13 +83,12 @@ class MPSModelServer : Disposable { override fun run(output: java.lang.StringBuilder): Boolean { var allSmart = true - val projects = ProjectManager.getInstance().openedProjects - for (project in projects) { + for (project in getMPSProjects()) { project.repository.modelAccess.runReadAction { val indexerDone = !DumbService.getInstance(ProjectHelper.toIdeaProject(project)).isDumb if (!indexerDone) { - output.append(" indexer running on project ").append(project.name) + output.append(" indexer running on project ").append(project.toString()) allSmart = false } } @@ -77,10 +103,10 @@ class MPSModelServer : Disposable { get() = false override fun run(output: StringBuilder): Boolean { - val projects = ProjectManager.getInstance().openedProjects + val projects = getMPSProjects() output.append("${projects.size} projects found") - projects.forEach { output.append(" ${it.name}") } - return ProjectManager.getInstance().openedProjects.isNotEmpty() + projects.forEach { output.append(" $it") } + return projects.isNotEmpty() } }) .healthCheck(object : LightModelServer.IHealthCheck { @@ -90,13 +116,13 @@ class MPSModelServer : Disposable { get() = false override fun run(output: StringBuilder): Boolean { - val projects = ProjectManager.getInstance().openedProjects.filterIsInstance() + val projects = getMPSProjects() for (project in projects) { val modules = project.projectModules val virtualFolders = modules .mapNotNull { project.getPath(it)?.virtualFolder } .filter { it.isNotEmpty() } - output.append("project ${project.name} contains ${modules.size} modules with ${virtualFolders.size} virtual folders") + output.append("project $project contains ${modules.size} modules with ${virtualFolders.size} virtual folders") if (virtualFolders.isNotEmpty()) return true } return false @@ -121,18 +147,8 @@ class MPSModelServer : Disposable { } } -class MPSModelServerDynamicPluginListener : DynamicPluginListener { - override fun pluginLoaded(pluginDescriptor: IdeaPluginDescriptor) { - service().ensureStarted() - } -} - -class MPSModelServerAppLifecycleListener : AppLifecycleListener { - override fun appStarting(projectFromCommandLine: Project?) { - service().ensureStarted() - } - - override fun appStarted() { - service().ensureStarted() +class MPSModelServerStartupActivity : StartupActivity.Background { + override fun runActivity(project: Project) { + project.service() // just ensure it's initialized } } diff --git a/mps-model-server-plugin/src/main/resources/META-INF/plugin.xml b/mps-model-server-plugin/src/main/resources/META-INF/plugin.xml index 5e32aad006..fa3588be5a 100644 --- a/mps-model-server-plugin/src/main/resources/META-INF/plugin.xml +++ b/mps-model-server-plugin/src/main/resources/META-INF/plugin.xml @@ -19,20 +19,12 @@ - com.intellij.modules.platform - - - - - + com.intellij.modules.mps + jetbrains.mps.core - +