Skip to content

Commit

Permalink
feat(mps-model-adapters): support for MPS 2020.3
Browse files Browse the repository at this point in the history
  • Loading branch information
slisson committed Jan 28, 2025
1 parent d364c0d commit f9401cf
Show file tree
Hide file tree
Showing 14 changed files with 42 additions and 60 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/mps-compatibility.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
strategy:
matrix:
version:
- "2020.3"
- "2021.1"
- "2021.2"
- "2021.3"
Expand All @@ -42,6 +43,7 @@ jobs:
run: >-
./gradlew --build-cache
:bulk-model-sync-mps:build
:bulk-model-sync-lib:mps-test:build
:metamodel-export:build
:mps-model-adapters:build
:mps-model-adapters-plugin:build
Expand Down
11 changes: 6 additions & 5 deletions build-logic/src/main/kotlin/org/modelix/CopyMps.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ val Project.mpsVersion: String get() {
"2021.1" to "2021.1.4",
"2021.2" to "2021.2.6",
"2021.3" to "2021.3.5",
"2022.2" to "2022.2.3",
"2022.3" to "2022.3.1",
"2023.2" to "2023.2",
"2023.3" to "2023.3",
"2024.1" to "2024.1-EAP1",
"2022.2" to "2022.2.4",
"2022.3" to "2022.3.3",
"2023.2" to "2023.2.2",
"2023.3" to "2023.3.2",
"2024.1" to "2024.1.1",
"2024.3" to "2024.3",
)[it],
) { "Unknown MPS version: $it" }
}
Expand Down
1 change: 1 addition & 0 deletions bulk-model-sync-lib/mps-test/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies {
testImplementation(libs.kotlin.serialization.json)
testImplementation(libs.xmlunit.matchers)
testImplementation(libs.jimfs)
testImplementation(libs.modelix.mpsApi)
}

intellij {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import com.intellij.openapi.project.ex.ProjectManagerEx
import com.intellij.openapi.util.Disposer
import com.intellij.testFramework.TestApplicationManager
import com.intellij.testFramework.UsefulTestCase
import com.intellij.util.io.delete
import jetbrains.mps.ide.ThreadUtils
import jetbrains.mps.ide.project.ProjectHelper
import jetbrains.mps.project.AbstractModule
import jetbrains.mps.project.MPSProject
import jetbrains.mps.smodel.Language
import jetbrains.mps.smodel.MPSModuleRepository
import org.jetbrains.mps.openapi.model.EditableSModel
import org.jetbrains.mps.openapi.model.SaveOptions
import org.modelix.model.api.PBranch
import org.modelix.model.api.getRootNode
import org.modelix.model.client.IdGenerator
Expand All @@ -25,21 +25,20 @@ import org.modelix.model.data.asData
import org.modelix.model.lazy.CLTree
import org.modelix.model.lazy.CLVersion
import org.modelix.model.lazy.ObjectStoreCache
import org.modelix.model.mpsadapters.MPSContextProject
import org.modelix.model.mpsadapters.asReadableNode
import org.modelix.model.mpsadapters.asWritableNode
import org.modelix.model.persistent.MapBaseStore
import org.modelix.model.sync.bulk.ModelSynchronizer
import org.modelix.model.sync.bulk.NodeAssociationFromModelServer
import org.modelix.model.sync.bulk.NodeAssociationToModelServer
import org.modelix.mps.api.ModelixMpsApi
import org.modelix.mps.model.sync.bulk.MPSProjectSyncFilter
import org.w3c.dom.Element
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.absolute
import kotlin.io.path.deleteRecursively

class RecreateProjectFromModelServerTest : UsefulTestCase() {

Expand Down Expand Up @@ -114,7 +113,7 @@ class RecreateProjectFromModelServerTest : UsefulTestCase() {
targetRoot = mpsRoot,
nodeAssociation = NodeAssociationFromModelServer(branch, mpsRoot.getModel()),
)
MPSContextProject.contextValue.computeWith(mpsProject) {
ModelixMpsApi.runWithProject(mpsProject) {
modelSynchronizer.synchronize()
}
}
Expand Down Expand Up @@ -145,7 +144,7 @@ class RecreateProjectFromModelServerTest : UsefulTestCase() {
val projectDirParent = Path.of("build", "test-projects").absolute()
projectDirParent.toFile().mkdirs()
val projectDir = Files.createTempDirectory(projectDirParent, "mps-project")
projectDir.deleteRecursively()
projectDir.delete(recursively = true)
projectDir.toFile().mkdirs()
projectDir.toFile().deleteOnExit()
val options = OpenProjectTask().withProjectName("test-project")
Expand Down Expand Up @@ -223,7 +222,7 @@ private fun Project.captureFileContents(): Map<String, String> {
module as AbstractModule
module.save()
for (model in module.models.filterIsInstance<EditableSModel>()) {
model.save(SaveOptions.FORCE)
ModelixMpsApi.forceSave(model)
}
}
}
Expand Down
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ dokka-base = { group = "org.jetbrains.dokka", name = "dokka-base", version.ref="

modelix-buildtools-gradle = { group = "org.modelix.mps", name = "build-tools-gradle", version.ref = "modelixBuildtools"}
modelix-buildtools-lib = { group = "org.modelix.mps", name = "build-tools-lib", version.ref = "modelixBuildtools"}
modelix-mpsApi = { group = "org.modelix.mps", name = "stable-api", version = "1.1.0" }

micrometer-registry-prometheus = { group = "io.micrometer", name = "micrometer-registry-prometheus", version.ref = "micrometer"}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.modelix.model.api.BuiltinLanguages
import org.modelix.model.api.ConceptReference
import org.modelix.model.api.INode
import org.modelix.model.api.IReplaceableNode
import kotlin.test.assertFailsWith

class ReplaceNodeTest : MpsAdaptersTestBase("SimpleProject") {

Expand Down Expand Up @@ -86,23 +87,23 @@ class ReplaceNodeTest : MpsAdaptersTestBase("SimpleProject") {
assertEquals(newConcept, newNode.getConceptReference())
}

fun `test fail to replace node with null concept`() = runCommandOnEDT {
fun `test fail to replace node with null concept`(): Unit = runCommandOnEDT {
val rootNode = getRootUnderTest()
val nodeToReplace = rootNode.allChildren.first() as IReplaceableNode

val expectedMessage = "Cannot replace node `method1` with a null concept. Explicitly specify a concept (e.g., `BaseConcept`)."
assertThrows(IllegalArgumentException::class.java, expectedMessage) {
assertFailsWith(IllegalArgumentException::class, expectedMessage) {
nodeToReplace.replaceNode(null)
}
}

fun `test fail to replace node with non mps concept`() = runCommandOnEDT {
fun `test fail to replace node with non mps concept`(): Unit = runCommandOnEDT {
val rootNode = getRootUnderTest()
val nodeToReplace = rootNode.allChildren.first() as IReplaceableNode
val newConcept = ConceptReference("notMpsConcept")

val expectedMessage = "Concept UID `notMpsConcept` cannot be parsed as MPS concept."
assertThrows(IllegalArgumentException::class.java, expectedMessage) {
assertFailsWith(IllegalArgumentException::class, expectedMessage) {
nodeToReplace.replaceNode(newConcept)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<project version="4">
<component name="MPSProject">
<projectModules>
<modulePath path="$PROJECT_DIR$/solutions/Solution1/Solution1.msd" folder="" />
<modulePath path="$PROJECT_DIR$/solutions/Solution1/Solution1.msd" folder="myFolder" />
</projectModules>
</component>
</project>
1 change: 1 addition & 0 deletions mps-model-adapters/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ dependencies {
implementation(libs.trove4j)
implementation(kotlin("stdlib"))
implementation(libs.kotlin.logging)
implementation(libs.modelix.mpsApi)
}

group = "org.modelix.mps"
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ package org.modelix.model.mpsadapters
import jetbrains.mps.persistence.MementoImpl
import jetbrains.mps.project.AbstractModule
import jetbrains.mps.project.DevKit
import jetbrains.mps.project.MPSProject
import jetbrains.mps.project.ModuleId
import jetbrains.mps.project.ProjectBase
import jetbrains.mps.project.ProjectManager
import jetbrains.mps.project.Solution
import jetbrains.mps.project.facets.JavaModuleFacet
import jetbrains.mps.smodel.Generator
Expand All @@ -30,6 +29,7 @@ import org.modelix.model.api.IReadableNode
import org.modelix.model.api.IReferenceLinkReference
import org.modelix.model.api.IWritableNode
import org.modelix.model.data.asData
import org.modelix.mps.api.ModelixMpsApi
import java.util.UUID

fun MPSModuleAsNode(module: SModule) = MPSModuleAsNode.create(module)
Expand All @@ -55,16 +55,11 @@ abstract class MPSModuleAsNode<E : SModule> : MPSGenericNodeAdapter<E>() {
},
BuiltinLanguages.jetbrains_mps_lang_core.BaseConcept.virtualPackage.toReference() to object : IPropertyAccessor<SModule> {
override fun read(element: SModule): String? {
return ProjectManager.getInstance().openedProjects.asSequence()
.filterIsInstance<ProjectBase>()
.mapNotNull { it.getPath(element) }
.firstOrNull()
?.virtualFolder
?.takeIf { it.isNotEmpty() }
return ModelixMpsApi.getVirtualFolder(element)
}

override fun write(element: SModule, value: String?) {
MPSContextProject.contextValue.getValue().setVirtualFolder(element, value ?: "")
ModelixMpsApi.setVirtualFolder(element, value)
}
},
BuiltinLanguages.MPSRepositoryConcepts.Module.id.toReference() to object : IPropertyAccessor<SModule> {
Expand Down Expand Up @@ -318,7 +313,7 @@ data class MPSLanguageAsNode(override val module: Language) : MPSModuleAsNode<La
index: Int,
sourceNode: SpecWithResolvedConcept,
): IWritableNode {
return GeneratorProducer(MPSContextProject.contextValue.getValue()).create(
return GeneratorProducer(ModelixMpsApi.getMPSProjects().first() as MPSProject).create(
element,
sourceNode.getNode().getPropertyValue(BuiltinLanguages.jetbrains_mps_lang_core.INamedConcept.name.toReference())!!,
sourceNode.getNode().getPropertyValue(BuiltinLanguages.MPSRepositoryConcepts.Module.id.toReference())!!.let { ModuleId.fromString(it) },
Expand All @@ -342,6 +337,7 @@ data class MPSDevkitAsNode(override val module: DevKit) : MPSModuleAsNode<DevKit
val originalRef = requireNotNull(refNode.getReferenceTargetRef(BuiltinLanguages.MPSRepositoryConcepts.ModuleReference.module.toReference())) {
"Reference to module is not set: ${refNode.asLegacyNode().asData().toJson()}"
}
@Suppress("removal")
MPSArea(contextModule.repository ?: MPSModuleRepository.getInstance()).resolveNode(originalRef)?.asWritableNode()
}
checkNotNull(moduleNode)
Expand Down Expand Up @@ -425,8 +421,9 @@ private fun <T : SModel> Iterable<T>.withoutDescriptorModel(): List<T> {

private fun SModule.getCompileInMPS(): Boolean {
val module = this
if (module is DevKit || module !is AbstractModule) {
if (module !is Solution) {
return false
}
return module.moduleDescriptor?.compileInMPS ?: false
@Suppress("removal")
return module.moduleDescriptor.compileInMPS
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.modelix.model.api.INodeReference
import org.modelix.model.api.IProperty
import org.modelix.model.api.IReferenceLink
import org.modelix.model.area.IArea
import org.modelix.mps.api.ModelixMpsApi

data class MPSProjectModuleAsNode(val project: ProjectBase, val module: SModule) : IDefaultNodeAdapter {

Expand Down Expand Up @@ -39,7 +40,7 @@ data class MPSProjectModuleAsNode(val project: ProjectBase, val module: SModule)

override fun getPropertyValue(property: IProperty): String? {
return if (property.conformsTo(BuiltinLanguages.MPSRepositoryConcepts.ProjectModule.virtualFolder)) {
project.getPath(module)?.virtualFolder
ModelixMpsApi.getVirtualFolders(module).firstOrNull()
} else {
null
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.modelix.model.mpsadapters

import jetbrains.mps.project.MPSProject
import jetbrains.mps.project.ModuleId
import jetbrains.mps.project.ProjectBase
import jetbrains.mps.project.ProjectManager
import jetbrains.mps.smodel.Generator
import jetbrains.mps.smodel.tempmodel.TempModule
import jetbrains.mps.smodel.tempmodel.TempModule2
Expand All @@ -18,6 +18,7 @@ import org.modelix.model.api.IReadableNode
import org.modelix.model.api.IReferenceLinkReference
import org.modelix.model.api.IWritableNode
import org.modelix.model.api.NullChildLinkReference
import org.modelix.mps.api.ModelixMpsApi

fun SRepository.asLegacyNode(): INode = MPSRepositoryAsNode(this).asLegacyNode()
fun SRepository.asWritableNode(): IWritableNode = MPSRepositoryAsNode(this)
Expand All @@ -41,19 +42,19 @@ data class MPSRepositoryAsNode(@get:JvmName("getRepository_") val repository: SR
): IWritableNode {
return when (sourceNode.getConceptReference()) {
BuiltinLanguages.MPSRepositoryConcepts.Solution.getReference() -> {
SolutionProducer(MPSContextProject.contextValue.getValue()).create(
SolutionProducer(ModelixMpsApi.getMPSProject() as MPSProject).create(
sourceNode.getNode().getPropertyValue(BuiltinLanguages.jetbrains_mps_lang_core.INamedConcept.name.toReference())!!,
sourceNode.getNode().getPropertyValue(BuiltinLanguages.MPSRepositoryConcepts.Module.id.toReference())!!.let { ModuleId.fromString(it) },
).let { MPSModuleAsNode(it) }
}
BuiltinLanguages.MPSRepositoryConcepts.Language.getReference() -> {
LanguageProducer(MPSContextProject.contextValue.getValue()).create(
LanguageProducer(ModelixMpsApi.getMPSProject() as MPSProject).create(
sourceNode.getNode().getPropertyValue(BuiltinLanguages.jetbrains_mps_lang_core.INamedConcept.name.toReference())!!,
sourceNode.getNode().getPropertyValue(BuiltinLanguages.MPSRepositoryConcepts.Module.id.toReference())!!.let { ModuleId.fromString(it) },
).let { MPSModuleAsNode(it) }
}
BuiltinLanguages.MPSRepositoryConcepts.DevKit.getReference() -> {
DevkitProducer(MPSContextProject.contextValue.getValue()).create(
DevkitProducer(ModelixMpsApi.getMPSProject() as MPSProject).create(
sourceNode.getNode().getPropertyValue(BuiltinLanguages.jetbrains_mps_lang_core.INamedConcept.name.toReference())!!,
sourceNode.getNode().getPropertyValue(BuiltinLanguages.MPSRepositoryConcepts.Module.id.toReference())!!.let { ModuleId.fromString(it) },
).let { MPSModuleAsNode(it) }
Expand All @@ -69,10 +70,8 @@ data class MPSRepositoryAsNode(@get:JvmName("getRepository_") val repository: SR
},
BuiltinLanguages.MPSRepositoryConcepts.Repository.projects.toReference() to object : IChildAccessor<SRepository> {
override fun read(element: SRepository): List<IWritableNode> {
return ProjectManager.getInstance().openedProjects
.filterIsInstance<ProjectBase>()
.plus(listOfNotNull(MPSContextProject.contextValue.getValueOrNull()))
.map { MPSProjectAsNode(it).asWritableNode() }
return ModelixMpsApi.getMPSProjects()
.map { MPSProjectAsNode(it as ProjectBase).asWritableNode() }
}
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.modelix.model.api.ISyncTargetNode
import org.modelix.model.api.IWritableNode
import org.modelix.model.api.NewNodeSpec
import org.modelix.model.api.meta.NullConcept
import org.modelix.mps.api.ModelixMpsApi

data class MPSWritableNode(val node: SNode) : IWritableNode, ISyncTargetNode {
override fun getModel(): IMutableModel {
Expand Down Expand Up @@ -97,7 +98,7 @@ data class MPSWritableNode(val node: SNode) : IWritableNode, ISyncTargetNode {
}

node.properties.forEach { newNode.setProperty(it, node.getProperty(it)) }
node.references.forEach { newNode.setReference(it.link, it.targetNodeReference) }
node.references.forEach { ModelixMpsApi.setReference(newNode, it.link, it.targetNodeReference) }
node.children.forEach { child ->
val link = checkNotNull(child.containmentLink) { "Containment link of child node not found" }
node.removeChild(child)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import jetbrains.mps.project.structure.modules.SolutionDescriptor
import jetbrains.mps.smodel.GeneralModuleFactory
import jetbrains.mps.smodel.Generator
import jetbrains.mps.smodel.Language
import jetbrains.mps.smodel.ModuleDependencyVersions
import jetbrains.mps.smodel.language.LanguageRegistry
import jetbrains.mps.vfs.IFile

class SolutionProducer(private val myProject: MPSProject) {
Expand All @@ -32,10 +30,6 @@ class SolutionProducer(private val myProject: MPSProject) {
val descriptor: SolutionDescriptor = createSolutionDescriptor(namespace, id, descriptorFile)
val module = GeneralModuleFactory().instantiate(descriptor, descriptorFile) as Solution
myProject.addModule(module)
ModuleDependencyVersions(
myProject.getComponent(LanguageRegistry::class.java),
myProject.repository,
).update(module)
module.save()
return module
}
Expand Down Expand Up @@ -72,10 +66,6 @@ class LanguageProducer(private val myProject: MPSProject) {
val descriptor = createDescriptor(namespace, id, descriptorFile)
val module = GeneralModuleFactory().instantiate(descriptor, descriptorFile) as Language
myProject.addModule(module)
ModuleDependencyVersions(
myProject.getComponent(LanguageRegistry::class.java),
myProject.repository,
).update(module)
module.save()
return module
}
Expand Down Expand Up @@ -147,10 +137,6 @@ class DevkitProducer(private val myProject: MPSProject) {
val descriptor = createDescriptor(namespace, id, descriptorFile)
val module = GeneralModuleFactory().instantiate(descriptor, descriptorFile) as DevKit
myProject.addModule(module)
ModuleDependencyVersions(
myProject.getComponent(LanguageRegistry::class.java),
myProject.repository,
).update(module)
module.save()
return module
}
Expand Down

0 comments on commit f9401cf

Please sign in to comment.