Skip to content

Commit 282bedf

Browse files
authored
feat(mps-sync-plugin): synchronizing read-only modules and models (#154)
* feat(mps-sync-plugin): transform read-only model imports * feat(mps-sync-plugin): transform read-only module dependencies * feat(mps-sync-plugin): disable the sync and unbind actions on read-only models and modules * feat(mps-sync-plugin): transform read-only node references * fix(mps-sync-plugin-lib): serialize MPSModelImportReference by hand to avoid a serializer not found exception at runtime * fix(mps-sync-plugin-lib): move creating read-only model import to a separate method because we have to do some more checks and steps than just simply creating the MPSModelImportReference * fix(mps-sync-plugin-lib): encapsulate the MPSNodeReference in a NodeReference otherwise the reference cannot be serialized * fix(mps-sync-plugin-lib): setting a reference for a read-only node * fix(mps-sync-plugin-lib): fix cahing read-only model import during modelix traversal * fix(mps-sync-plugin-lib): model imports can be added and resolved at any time Track if the ResolvableModelImport has been resolved (i.e. synced to the cloud) and if so then remove it from the pending this. This way, we can sync model imports directly after they were added to the model. * refactor(mps-sync-plugin-lib): do not use SNode, SModel, SModule in the cache Because they may change behind-the-scenes without any warning. As a consequence, they will not be found in the cache as keys, even though they did not change. (MODELIX-787) * feat(mps-sync-plugin-lib): add SRepository as a new field to the ServiceLocator so the MPS Repository is always directly accessible and we do not have to go to the MPS Project first * fix(mps-sync-plugin-lib): create mapping link for the read-only model imports * fix(mps-sync-plugin-lib): remove outgoing model and module dependency mappings from the cache, when the corresponding ModelImport, ModuleDependency, LanguageDependency, DevKitDependency is removed * refactor(mps-sync-plugin-lib): reclassify missed node removal error to warning * fix(mps-sync-plugin-lib): add null-checks where returned object may be null * refactor(mps-sync-plugin-lib): inline a variable that is used only once
1 parent 90fad13 commit 282bedf

File tree

20 files changed

+349
-132
lines changed

20 files changed

+349
-132
lines changed

mps-sync-plugin-lib/src/main/kotlin/org/modelix/mps/sync/SyncServiceImpl.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class SyncServiceImpl : ISyncService, InjectableService {
5555
get() = serviceLocator.branchRegistry
5656

5757
private val mpsRepository: SRepository
58-
get() = serviceLocator.mpsProject.repository
58+
get() = serviceLocator.mpsRepository
5959

6060
private val languageRepository: MPSLanguageRepository
6161
get() = serviceLocator.languageRepository

mps-sync-plugin-lib/src/main/kotlin/org/modelix/mps/sync/modelix/branch/BranchRegistry.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616

1717
package org.modelix.mps.sync.modelix.branch
1818

19-
import jetbrains.mps.project.MPSProject
2019
import kotlinx.coroutines.CoroutineScope
2120
import kotlinx.coroutines.runBlocking
21+
import org.jetbrains.mps.openapi.module.SRepository
2222
import org.modelix.kotlin.utils.UnstableModelixFeature
2323
import org.modelix.model.api.IBranch
2424
import org.modelix.model.client2.ModelClientV2
@@ -38,8 +38,8 @@ class BranchRegistry : InjectableService {
3838

3939
private lateinit var serviceLocator: ServiceLocator
4040

41-
private val mpsProject: MPSProject
42-
get() = serviceLocator.mpsProject
41+
private val mpsRepository: SRepository
42+
get() = serviceLocator.mpsRepository
4343

4444
var model: ReplicatedModel? = null
4545
private set
@@ -91,7 +91,7 @@ class BranchRegistry : InjectableService {
9191
this.client = client
9292

9393
val repositoryChangeListener = RepositoryChangeListener(branch, serviceLocator)
94-
mpsProject.repository.addRepositoryListener(repositoryChangeListener)
94+
mpsRepository.addRepositoryListener(repositoryChangeListener)
9595
repoChangeListener = repositoryChangeListener
9696

9797
return model!!
@@ -100,7 +100,7 @@ class BranchRegistry : InjectableService {
100100
override fun dispose() {
101101
val branch = getBranch() ?: return
102102
branch.removeListener(branchListener)
103-
mpsProject.repository.removeRepositoryListener(repoChangeListener)
103+
mpsRepository.removeRepositoryListener(repoChangeListener)
104104

105105
model?.dispose()
106106

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.modelix.mps.sync.modelix.util
2+
3+
import org.modelix.model.api.PropertyFromName
4+
5+
object ModuleDependencyConstants {
6+
val MODULE_DEPENDENCY_IS_READ_ONLY_PROPERTY = PropertyFromName("isReadOnly")
7+
}

mps-sync-plugin-lib/src/main/kotlin/org/modelix/mps/sync/mps/factories/SNodeFactory.kt

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@ import org.modelix.kotlin.utils.UnstableModelixFeature
2828
import org.modelix.model.api.BuiltinLanguages
2929
import org.modelix.model.api.IBranch
3030
import org.modelix.model.api.INode
31+
import org.modelix.model.api.PNodeReference
3132
import org.modelix.model.api.getNode
33+
import org.modelix.model.mpsadapters.MPSArea
3234
import org.modelix.model.mpsadapters.MPSLanguageRepository
35+
import org.modelix.model.mpsadapters.MPSNode
3336
import org.modelix.model.mpsadapters.MPSProperty
3437
import org.modelix.model.mpsadapters.MPSReferenceLink
3538
import org.modelix.mps.sync.modelix.util.getMpsNodeId
@@ -53,6 +56,7 @@ class SNodeFactory(
5356
private val nodeMap = serviceLocator.nodeMap
5457
private val syncQueue = serviceLocator.syncQueue
5558
private val futuresWaitQueue = serviceLocator.futuresWaitQueue
59+
private val mpsRepository = serviceLocator.mpsRepository
5660

5761
private val resolvableReferences = mutableListOf<ResolvableReference>()
5862

@@ -125,17 +129,32 @@ class SNodeFactory(
125129
}
126130

127131
private fun prepareLinkReferences(iNode: INode) {
128-
iNode.getAllReferenceTargets().forEach {
129-
val sourceNodeId = iNode.nodeIdAsLong()
130-
val source = nodeMap.getNode(sourceNodeId)!!
132+
val sourceNodeId = iNode.nodeIdAsLong()
133+
val source = nodeMap.getNode(sourceNodeId)!!
131134

135+
iNode.getAllReferenceTargetRefs().forEach {
132136
val reference = when (val referenceLink = it.first) {
133137
is MPSReferenceLink -> referenceLink.link
134138
else -> source.concept.referenceLinks.first { refLink -> refLink.name == referenceLink.getSimpleName() }
135139
}
136140

137-
val targetNodeId = it.second.nodeIdAsLong()
138-
resolvableReferences.add(ResolvableReference(source, reference, targetNodeId))
141+
val targetNodeReference = it.second
142+
val serializedRef = targetNodeReference.serialize()
143+
val targetIsAnINode = PNodeReference.tryDeserialize(serializedRef) != null
144+
145+
if (targetIsAnINode) {
146+
// delay the reference resolution, because the target node might not have been transformed yet
147+
val targetNode = iNode.getReferenceTarget(it.first)
148+
?: throw IllegalArgumentException("PNodeReference exists, but PNode cannot be resolved: '$serializedRef'")
149+
val targetNodeId = targetNode.nodeIdAsLong()
150+
resolvableReferences.add(ResolvableReference(source, reference, targetNodeId))
151+
} else {
152+
// target node is an existing SNode
153+
val area = MPSArea(mpsRepository)
154+
val mpsNode = area.resolveNode(targetNodeReference) as MPSNode?
155+
requireNotNull(mpsNode) { "SNode identified by Node $sourceNodeId is not found." }
156+
source.setReferenceTarget(reference, mpsNode.node)
157+
}
139158
}
140159
}
141160

mps-sync-plugin-lib/src/main/kotlin/org/modelix/mps/sync/mps/services/ServiceLocator.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.intellij.openapi.Disposable
44
import com.intellij.openapi.application.ApplicationManager
55
import com.intellij.openapi.components.Service
66
import com.intellij.openapi.project.Project
7+
import org.jetbrains.mps.openapi.module.SRepository
78
import org.modelix.kotlin.utils.UnstableModelixFeature
89
import org.modelix.mps.sync.SyncServiceImpl
910
import org.modelix.mps.sync.bindings.BindingsRegistry
@@ -40,6 +41,8 @@ class ServiceLocator(val project: Project) : Disposable {
4041
val futuresWaitQueue = FuturesWaitQueue()
4142

4243
val mpsProject = project.toMpsProject()
44+
val mpsRepository: SRepository
45+
get() = mpsProject.repository
4346

4447
val languageRepository = ApplicationManager.getApplication()
4548
.getService(MPSLanguageRepositoryProvider::class.java).mpsLanguageRepository

0 commit comments

Comments
 (0)