Skip to content

Commit

Permalink
compatibility with older MPS versions
Browse files Browse the repository at this point in the history
  • Loading branch information
slisson committed Feb 18, 2025
1 parent c8ab651 commit 24529db
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 50 deletions.
1 change: 1 addition & 0 deletions .github/workflows/mps-compatibility.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
timeout-minutes: 60

strategy:
fail-fast: false
matrix:
version:
- "2020.3"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,7 @@ data class MPSArea(val repository: SRepository) : IArea, IAreaReference {
}

override fun <T> executeRead(f: () -> T): T {
var result: T? = null
repository.modelAccess.runReadAction {
result = f()
}
return result!!
return repository.computeRead(f)
}

override fun <T> executeWrite(f: () -> T): T {
Expand Down Expand Up @@ -365,3 +361,11 @@ data class MPSArea(val repository: SRepository) : IArea, IAreaReference {
return repository.asLegacyNode()
}
}

fun <R> SRepository.computeRead(body: () -> R): R {
var result: R? = null
modelAccess.runReadAction {
result = body()
}
return result as R
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package org.modelix.model.mpsadapters

import jetbrains.mps.persistence.MementoImpl
import jetbrains.mps.project.facets.JavaModuleFacet
import jetbrains.mps.smodel.Generator
import jetbrains.mps.util.MacroHelper
import jetbrains.mps.util.MacrosFactory
import org.jetbrains.mps.openapi.module.SRepository
import org.jetbrains.mps.openapi.persistence.Memento
Expand Down Expand Up @@ -30,15 +31,24 @@ data class MPSJavaModuleFacetAsNode(val facet: JavaModuleFacet) : MPSGenericNode
},
BuiltinLanguages.MPSRepositoryConcepts.JavaModuleFacet.path.toReference() to object : IPropertyAccessor<JavaModuleFacet> {
override fun read(facet: JavaModuleFacet): String? {
return facet.classesGen?.let { MacrosFactory().module(facet.module).shrinkPath(it.path) }
// return facet.classesGen?.let { facet.macroHelper().shrinkPath(it.path) }
return null
}

override fun write(element: JavaModuleFacet, value: String?) {
element.classesGen
val memento = MementoImpl()
element.save(memento)
memento.getOrCreateChild("classes").put("path", value?.let { MacrosFactory().module(element.module).expandPath(it) })
element.load(memento)
// val memento = MementoImpl()
// element.save(memento)
// memento.getOrCreateChild("classes").let {
// it.put("generated", "true")
// it.put("path", value.also { println("${element.module} / path = $it") })
// }
// element.load(memento)
}

private fun JavaModuleFacet.macroHelper(): MacroHelper {
return module
.let { if (it is Generator) it.sourceLanguage().sourceModule else it }
.let { MacrosFactory().module(it) }
}
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,10 @@ abstract class MPSModuleAsNode<E : SModule> : MPSGenericNodeAdapter<E>() {
val moduleDescriptor = checkNotNull(module.moduleDescriptor) { "Has no moduleDescriptor: $module" }
val newFacet = FacetsFacade.getInstance().getFacetFactory(JavaModuleFacet.FACET_TYPE)!!.create(element) as JavaModuleFacetImpl
newFacet.load(MementoImpl())
val moduleDir = if (element is Generator) element.getGeneratorLocation() else module.moduleSourceDir
if (moduleDir != null) {
newFacet.setGeneratedClassesLocation(moduleDir.findChild(AbstractModule.CLASSES_GEN))
}
// val moduleDir = if (element is Generator) element.getGeneratorLocation() else module.moduleSourceDir
// if (moduleDir != null) {
// newFacet.setGeneratedClassesLocation(moduleDir.findChild(AbstractModule.CLASSES_GEN))
// }
moduleDescriptor.addFacetDescriptor(newFacet)
module.setModuleDescriptor(moduleDescriptor) // notify listeners
read(element).filterIsInstance<MPSJavaModuleFacetAsNode>().single()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ fun org.jetbrains.mps.openapi.model.SNodeId.tryDecodeModelixReference(): NodeRef
}

fun INodeReference.encodeAsForeignId(): SNodeId {
return SNodeId.Foreign.fromIdNoPrefix("mx" + Hex.encodeHexString(serialize().toByteArray()))
return SNodeId.Foreign("~mx" + Hex.encodeHexString(serialize().toByteArray()))
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
@file:Suppress("removal")

package org.modelix.model.mpsadapters

import jetbrains.mps.extapi.persistence.FileBasedModelRoot
import jetbrains.mps.ide.project.ProjectHelper
import jetbrains.mps.persistence.DefaultModelRoot
import jetbrains.mps.project.AbstractModule
import jetbrains.mps.project.DevKit
import jetbrains.mps.project.MPSExtentions
import jetbrains.mps.project.MPSProject
Expand Down Expand Up @@ -37,7 +40,9 @@ class SolutionProducer(private val myProject: MPSProject) {

private fun createSolutionDescriptor(namespace: String, id: ModuleId, descriptorFile: IFile): SolutionDescriptor {
val descriptor = SolutionDescriptor()
descriptor.outputRoot = "\${module}/source_gen"
// using outputPath instead of outputRoot for backwards compatibility
// descriptor.outputRoot = "\${module}/source_gen"
descriptor.outputPath = descriptorFile.parent!!.findChild("source_gen").path
descriptor.namespace = namespace
descriptor.id = id
val moduleLocation = descriptorFile.parent
Expand Down Expand Up @@ -74,7 +79,9 @@ class LanguageProducer(private val myProject: MPSProject) {

private fun createDescriptor(namespace: String, id: ModuleId, descriptorFile: IFile): LanguageDescriptor {
val descriptor = LanguageDescriptor()
descriptor.outputRoot = "\${module}/source_gen"
// using genPath instead of outputRoot for backwards compatibility
// descriptor.outputRoot = "\${module}/source_gen"
descriptor.genPath = descriptorFile.parent!!.findChild("source_gen").path
descriptor.namespace = namespace
descriptor.id = id
val moduleLocation = descriptorFile.parent
Expand Down Expand Up @@ -127,7 +134,9 @@ class GeneratorProducer(private val myProject: MPSProject) {

private fun createDescriptor(namespace: String, id: ModuleId, alias: String?, generatorModuleLocation: IFile, templateModelsLocation: IFile?): GeneratorDescriptor {
val descriptor = GeneratorDescriptor()
descriptor.outputRoot = "\${module}/${generatorModuleLocation.name}/source_gen"
// using outputPath instead of outputRoot for backwards compatibility
// descriptor.outputRoot = "\${module}/${generatorModuleLocation.name}/source_gen"
descriptor.outputPath = generatorModuleLocation.findChild(AbstractModule.CLASSES_GEN).path
descriptor.namespace = namespace
descriptor.id = id
descriptor.alias = alias ?: "main"
Expand All @@ -142,7 +151,7 @@ class GeneratorProducer(private val myProject: MPSProject) {
}

fun Generator.getGeneratorLocation(): IFile? {
return modelRoots.filterIsInstance<FileBasedModelRoot>().firstNotNullOfOrNull { it.contentDirectory }
return modelRoots.filterIsInstance<FileBasedModelRoot>().mapNotNull { it.contentDirectory }.firstOrNull()
}

class DevkitProducer(private val myProject: MPSProject) {
Expand Down
3 changes: 0 additions & 3 deletions mps-sync-plugin3/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ tasks {
onlyIf {
!setOf(
"2020.3", // incompatible with the intellij plugin
"2021.2", // hangs when executed on CI
"2021.3", // hangs when executed on CI
"2022.2", // hangs when executed on CI
).contains(mpsMajorVersion)
}
jvmArgs("-Dintellij.platform.load.app.info.from.resources=true")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
@file:OptIn(ExperimentalTime::class)

package org.modelix.mps.sync3

import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import jetbrains.mps.ide.project.ProjectHelper
import jetbrains.mps.project.MPSProject
Expand All @@ -17,7 +18,6 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import org.jetbrains.mps.openapi.module.SRepository
import org.modelix.model.IVersion
import org.modelix.model.api.TreePointer
Expand All @@ -27,6 +27,7 @@ import org.modelix.model.client2.ModelClientV2
import org.modelix.model.client2.runWrite
import org.modelix.model.lazy.BranchReference
import org.modelix.model.mpsadapters.MPSRepositoryAsNode
import org.modelix.model.mpsadapters.computeRead
import org.modelix.model.sync.bulk.FullSyncFilter
import org.modelix.model.sync.bulk.InvalidatingVisitor
import org.modelix.model.sync.bulk.InvalidationTree
Expand All @@ -38,25 +39,24 @@ import org.modelix.mps.api.ModelixMpsApi
import org.modelix.mps.model.sync.bulk.MPSProjectSyncMask
import org.modelix.mps.sync3.Binding.Companion.LOG
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
import kotlin.math.roundToLong
import kotlin.time.ExperimentalTime

@Service(Service.Level.APP)
class AppLevelModelSyncService() : Disposable {

companion object {
fun getInstance(): AppLevelModelSyncService {
return ApplicationManager.getApplication().service<AppLevelModelSyncService>()
return ApplicationManager.getApplication().getService(AppLevelModelSyncService::class.java)
}
}

private val connections = LinkedHashMap<String, ServerConnection>()
private val coroutinesScope = CoroutineScope(Dispatchers.Default)
private val connectionCheckingJob = coroutinesScope.launchLoop(
BackoffStrategy(
initialDelay = 3.seconds,
maxDelay = 10.seconds,
initialDelay = 3_000,
maxDelay = 10_000,
factor = 1.2,
),
) {
Expand Down Expand Up @@ -210,7 +210,7 @@ class Binding(
while (reason != null) {
i++
if (i % 10 == 0) LOG.debug { "Still waiting for the synchronization to finish: $reason" }
delay(100.milliseconds)
delay(100)
reason = checkInSync()
}
return lastSyncedVersion.getValue()!!
Expand Down Expand Up @@ -347,13 +347,17 @@ class Binding(

private suspend fun <R> writeToMPS(body: () -> R): R {
val result = ArrayList<R>()
withContext(Dispatchers.EDT) {
repository.modelAccess.executeUndoTransparentCommand {
ModelixMpsApi.runWithProject(mpsProject) {
result += body()
ApplicationManager.getApplication().invokeAndWait({
ApplicationManager.getApplication().runWriteAction {
repository.modelAccess.executeUndoTransparentCommand {
ModelixMpsApi.runWithProject(mpsProject) {
result += body()
}
}
}
}
}, ModalityState.NON_MODAL)
// withContext(Dispatchers.Main) {
// }
return result.single()
}

Expand All @@ -379,7 +383,7 @@ class Binding(

val mpsProjects = listOf(mpsProject as MPSProject)
val client = client()
val newVersion = repository.modelAccess.computeReadAction {
val newVersion = repository.computeRead {
fun sync(invalidationTree: IIncrementalUpdateInformation): IVersion? {
return oldVersion.runWrite(client) { branch ->
ModelixMpsApi.runWithProject(mpsProject) {
Expand Down Expand Up @@ -449,14 +453,14 @@ suspend fun jobLoop(
}

class BackoffStrategy(
val initialDelay: Duration = 500.milliseconds,
val maxDelay: Duration = 10.seconds,
val initialDelay: Long = 500,
val maxDelay: Long = 10_000,
val factor: Double = 1.5,
) {
var currentDelay: Duration = initialDelay
var currentDelay: Long = initialDelay

fun failed() {
currentDelay = (currentDelay * factor).coerceAtMost(maxDelay)
currentDelay = (currentDelay * factor).roundToLong().coerceAtMost(maxDelay)
}

fun success() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package org.modelix.mps.sync3

import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.intellij.openapi.startup.ProjectActivity
import com.intellij.openapi.startup.StartupActivity

class ModelSyncStartupActivity : ProjectActivity {
override suspend fun execute(project: Project) {
class ModelSyncStartupActivity : StartupActivity {
override fun runActivity(project: Project) {
project.service<ModelSyncService>() // just ensure it's initialized
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package org.modelix.mps.sync3
import com.intellij.ide.impl.OpenProjectTask
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.project.ex.ProjectManagerEx
Expand Down Expand Up @@ -87,8 +87,10 @@ abstract class MPSTestBase : UsefulTestCase() {

protected suspend fun <R> command(body: () -> R): R {
var result: R? = null
withContext(Dispatchers.EDT) {
mpsProject.modelAccess.executeCommand { result = body() }
withContext(Dispatchers.Main) {
ApplicationManager.getApplication().invokeAndWait({
mpsProject.modelAccess.executeCommand { result = body() }
}, ModalityState.NON_MODAL)
}
return result as R
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ private fun normalizeXmlFile(content: String): String {
node.setAttribute("path", "$contentPath/$location")
}
}
"classes" -> {
node.removeAttribute("path")
}
"language", "solution", "generator" -> {
node.removeAttribute("generatorOutputPath")
}
}
}
return xmlToString(xml).lineSequence().filter { it.isNotBlank() }.joinToString("\n")
Expand Down

0 comments on commit 24529db

Please sign in to comment.