Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.modelix.mps.model.sync.bulk

import jetbrains.mps.project.MPSProject
import org.modelix.model.api.BuiltinLanguages
import org.modelix.model.api.IChildLinkReference
import org.modelix.model.api.IReadableNode
Expand All @@ -9,7 +8,7 @@
import org.modelix.model.mpsadapters.MPSProjectAsNode
import org.modelix.model.sync.bulk.IModelMask

class MPSProjectSyncMask(val projects: List<MPSProject>, val isMPSSide: Boolean) : IModelMask {
class MPSProjectSyncMask(val projects: List<MPSProjectAsNode>, val isMPSSide: Boolean) : IModelMask {

Check warning

Code scanning / detekt

MPSProjectSyncMask is missing required documentation. Warning

MPSProjectSyncMask is missing required documentation.

Check warning

Code scanning / detekt

The property projects is missing documentation. Warning

The property projects is missing documentation.

Check warning

Code scanning / detekt

The property isMPSSide is missing documentation. Warning

The property isMPSSide is missing documentation.

override fun <T : IReadableNode> filterChildren(
parent: IReadableNode,
Expand All @@ -21,15 +20,17 @@
role.matches(BuiltinLanguages.MPSRepositoryConcepts.Repository.tempModules.toReference()) -> emptyList()
role.matches(BuiltinLanguages.MPSRepositoryConcepts.Repository.modules.toReference()) -> {
if (isMPSSide) {
val included = projects.flatMap { it.projectModules }.map { MPSModuleAsNode(it).getNodeReference().serialize() }.toSet()
val included = projects
.flatMap { it.project.getModules() }
.map { MPSModuleAsNode(it).getNodeReference().serialize() }.toSet()
children.filter { included.contains(it.getNodeReference().serialize()) }
} else {
children
}
}
role.matches(BuiltinLanguages.MPSRepositoryConcepts.Repository.projects.toReference()) -> {
if (isMPSSide) {
val included = projects.map { MPSProjectAsNode(it).getNodeReference().serialize() }.toSet()
val included = projects.map { it.getNodeReference().serialize() }.toSet()
children.filter { included.contains(it.getNodeReference().serialize()) }
} else {
children
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@ object BuiltinLanguages {
uid = "0a7577d1-d4e5-431d-98b1-fae38f9aee80/474657388638618895/2206727074858242373",
).also(this::addProperty)

val isReadOnly = SimpleProperty(
"isReadOnly",
uid = "0a7577d1-d4e5-431d-98b1-fae38f9aee80/474657388638618895/4225291355523310000",
).also(this::addProperty)

val models = SimpleChildLink(
simpleName = "models",
isMultiple = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,5 @@
}
}
}

fun SAbstractConcept.toModelix() = MPSConcept(this)

Check warning

Code scanning / detekt

The function toModelix is missing documentation. Warning

The function toModelix is missing documentation.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ 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 org.modelix.mps.multiplatform.model.MPSModelReference

fun MPSModuleAsNode(module: SModule) = MPSModuleAsNode.create(module)

Expand Down Expand Up @@ -107,6 +108,22 @@ abstract class MPSModuleAsNode<E : SModule> : MPSGenericNodeAdapter<E>() {
(element as Solution).moduleDescriptor.compileInMPS = value.toBoolean()
}
},
BuiltinLanguages.MPSRepositoryConcepts.Module.isReadOnly.toReference() to object : IPropertyAccessor<SModule> {
override fun read(element: SModule): String? {
return element.isReadOnly.takeIf { it }?.toString()
}

override fun write(element: SModule, value: String?) {
if (read(element).toBoolean() == value.toBoolean()) return
check(element is Solution) {
"Property 'isReadOnly' can only be changed on Solutions, but ${element.moduleName} is a ${element.javaClass.simpleName}"
}
check(!element.isPackaged) {
"Property 'isReadOnly' can't be changed on packaged modules. [module=${element.moduleName}]"
}
element.moduleDescriptor.readOnlyStubModule(value.toBoolean())
}
},
)

private val referenceAccessors = listOf<Pair<IReferenceLinkReference, IReferenceAccessor<SModule>>>()
Expand All @@ -123,8 +140,10 @@ abstract class MPSModuleAsNode<E : SModule> : MPSGenericNodeAdapter<E>() {
return element.createModel(
name = sourceNode.getNode().getPropertyValue(BuiltinLanguages.jetbrains_mps_lang_core.INamedConcept.name.toReference())
?: "${element.moduleName}.unnamed",
id = sourceNode.getNode().getPropertyValue(BuiltinLanguages.MPSRepositoryConcepts.Model.id.toReference())
?.let { PersistenceFacade.getInstance().createModelId(it) } ?: SModelId.generate(),
id = MPSModelReference.tryConvert(sourceNode.getNode().getNodeReference())?.toMPS()?.modelId
?: sourceNode.getNode().getPropertyValue(BuiltinLanguages.MPSRepositoryConcepts.Model.id.toReference())
?.let { PersistenceFacade.getInstance().createModelId(it) }
?: SModelId.generate(),
).let { MPSModelAsNode(it) }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,25 @@
import org.modelix.mps.multiplatform.model.MPSModuleReference
import org.modelix.mps.multiplatform.model.MPSProjectReference

data class MPSProjectAsNode(val project: IMPSProject) : MPSGenericNodeAdapter<IMPSProject>() {
data class MPSProjectAsNode(private val id: MPSProjectReference, val project: IMPSProject) : MPSGenericNodeAdapter<MPSProjectAsNode>() {

Check warning

Code scanning / detekt

MPSProjectAsNode is missing required documentation. Warning

MPSProjectAsNode is missing required documentation.

Check warning

Code scanning / detekt

The property project is missing documentation. Warning

The property project is missing documentation.

constructor(project: IMPSProject) : this(MPSProjectReference(project), project)

companion object {
val CONTEXT_PROJECTS = ContextValue<List<IMPSProject>>(emptyList())
private val CONTEXT_PROJECTS = ContextValue<List<MPSProjectAsNode>>(emptyList())

fun getContextProject(): IMPSProject {
return CONTEXT_PROJECTS.getValueOrNull()?.lastOrNull() ?: MPSProjectAdapter(ModelixMpsApi.getMPSProject())
fun getContextProjectNode(): MPSProjectAsNode {

Check warning

Code scanning / detekt

The function getContextProjectNode is missing documentation. Warning

The function getContextProjectNode is missing documentation.
return CONTEXT_PROJECTS.getValueOrNull()?.lastOrNull() ?: MPSProjectAsNode(ModelixMpsApi.getMPSProject())
}

fun getContextProjects(): List<IMPSProject> {
fun getContextProject(): IMPSProject = getContextProjectNode().project

Check warning

Code scanning / detekt

The function getContextProject is missing documentation. Warning

The function getContextProject is missing documentation.

fun getContextProjectNodes(): List<MPSProjectAsNode> {

Check warning

Code scanning / detekt

The function getContextProjectNodes is missing documentation. Warning

The function getContextProjectNodes is missing documentation.
return CONTEXT_PROJECTS.getValueOrNull()?.takeIf { it.isNotEmpty() }
?: ModelixMpsApi.getMPSProjects().map { MPSProjectAdapter(it) }
?: ModelixMpsApi.getMPSProjects().map { MPSProjectAsNode(MPSProjectAdapter(it)) }
}

fun getAllProjects(): List<IMPSProject> {
return (
ModelixMpsApi.getMPSProjects().map { MPSProjectAdapter(it) } +
CONTEXT_PROJECTS.getValueOrNull().orEmpty()
).distinct()
}
fun getContextProjects(): List<IMPSProject> = getContextProjectNodes().map { it.project }

Check warning

Code scanning / detekt

The function getContextProjects is missing documentation. Warning

The function getContextProjects is missing documentation.

fun <R> runWithProject(project: org.jetbrains.mps.openapi.project.Project, body: () -> R): R {
return runWithProjects(listOf(project), body)
Expand All @@ -46,35 +45,45 @@
}
}

fun <R> runWithProjectNode(project: MPSProjectAsNode, body: () -> R): R {

Check warning

Code scanning / detekt

The function runWithProjectNode is missing documentation. Warning

The function runWithProjectNode is missing documentation.
return runWithProjectNodes(listOf(project), body)
}

fun <R> runWithProjectNodes(projects: List<MPSProjectAsNode>, body: () -> R): R {

Check warning

Code scanning / detekt

The function runWithProjectNodes is missing documentation. Warning

The function runWithProjectNodes is missing documentation.
if (projects.isEmpty()) return body()
val newProjects = CONTEXT_PROJECTS.getValueOrNull().orEmpty() + projects
return CONTEXT_PROJECTS.computeWith(newProjects) {
ModelixMpsApi.runWithRepository(projects.last().project.getRepository(), body)
}
}

fun <R> runWithProject(project: IMPSProject, body: () -> R): R {
return runWithProjects(listOf(project), body)
}

fun <R> runWithProjects(projects: List<IMPSProject>, body: () -> R): R {
if (projects.isEmpty()) return body()
return CONTEXT_PROJECTS.computeWith(CONTEXT_PROJECTS.getValueOrNull().orEmpty() + projects) {
ModelixMpsApi.runWithRepository(projects.last().getRepository(), body)
}
return runWithProjectNodes(projects.map { MPSProjectAsNode(it) }, body)
}

private val propertyAccessors: List<Pair<IPropertyReference, IPropertyAccessor<IMPSProject>>> = listOf(
BuiltinLanguages.jetbrains_mps_lang_core.INamedConcept.name.toReference() to object : IPropertyAccessor<IMPSProject> {
override fun read(element: IMPSProject): String? {
return element.getName()
private val propertyAccessors: List<Pair<IPropertyReference, IPropertyAccessor<MPSProjectAsNode>>> = listOf(
BuiltinLanguages.jetbrains_mps_lang_core.INamedConcept.name.toReference() to object : IPropertyAccessor<MPSProjectAsNode> {
override fun read(element: MPSProjectAsNode): String? {
return element.project.getName()
}

override fun write(element: IMPSProject, value: String?) {
element.setName(value ?: "")
override fun write(element: MPSProjectAsNode, value: String?) {
element.project.setName(value ?: "")

Check warning

Code scanning / detekt

This '?: ""' can be replaced with 'orEmpty()' call Warning

This '?: ""' can be replaced with 'orEmpty()' call
}
},
)
private val childAccessors: List<Pair<IChildLinkReference, IChildAccessor<IMPSProject>>> = listOf(
BuiltinLanguages.MPSRepositoryConcepts.Project.projectModules.toReference() to object : IChildAccessor<IMPSProject> {
override fun read(element: IMPSProject): List<IWritableNode> {
return element.getModules().map { MPSProjectModuleAsNode(element, it) }
private val childAccessors: List<Pair<IChildLinkReference, IChildAccessor<MPSProjectAsNode>>> = listOf(
BuiltinLanguages.MPSRepositoryConcepts.Project.projectModules.toReference() to object : IChildAccessor<MPSProjectAsNode> {
override fun read(element: MPSProjectAsNode): List<IWritableNode> {
return element.project.getModules().map { MPSProjectModuleAsNode(element, it) }
}

override fun addNew(element: IMPSProject, index: Int, sourceNode: SpecWithResolvedConcept): IWritableNode {
override fun addNew(element: MPSProjectAsNode, index: Int, sourceNode: SpecWithResolvedConcept): IWritableNode {
val targetModuleRef = requireNotNull(sourceNode.getNode().getReferenceTargetRef(BuiltinLanguages.MPSRepositoryConcepts.ModuleReference.module.toReference())) {
"Reference to module isn't set"
}
Expand All @@ -88,25 +97,25 @@
?: mpsTargetModuleRef.moduleId
).let { ModuleId.fromString(it) }
val ref = PersistenceFacade.getInstance().createModuleReference(targetId, targetName)
val resolvedModule = checkNotNull(ref.resolve(element.getRepository())) { "Module not found: $ref" }
element.addModule(resolvedModule)
val resolvedModule = checkNotNull(ref.resolve(element.project.getRepository())) { "Module not found: $ref" }
element.project.addModule(resolvedModule)
return MPSProjectModuleAsNode(element, resolvedModule)
}

override fun remove(element: IMPSProject, child: IWritableNode) {
element.removeModule((child as MPSProjectModuleAsNode).module)
override fun remove(element: MPSProjectAsNode, child: IWritableNode) {
element.project.removeModule((child as MPSProjectModuleAsNode).module)
}
},
BuiltinLanguages.MPSRepositoryConcepts.Project.modules.toReference() to object : IChildAccessor<IMPSProject> {
override fun read(element: IMPSProject): List<IWritableNode> {
BuiltinLanguages.MPSRepositoryConcepts.Project.modules.toReference() to object : IChildAccessor<MPSProjectAsNode> {
override fun read(element: MPSProjectAsNode): List<IWritableNode> {
return return emptyList() // modules child link is deprecated
}

override fun addNew(element: IMPSProject, index: Int, sourceNode: SpecWithResolvedConcept): IWritableNode {
override fun addNew(element: MPSProjectAsNode, index: Int, sourceNode: SpecWithResolvedConcept): IWritableNode {
throw UnsupportedOperationException("read only")
}

override fun remove(element: IMPSProject, child: IWritableNode) {
override fun remove(element: MPSProjectAsNode, child: IWritableNode) {
throw UnsupportedOperationException("read only")
}
},
Expand All @@ -115,19 +124,19 @@

constructor(mpsProject: org.jetbrains.mps.openapi.project.Project) : this(MPSProjectAdapter(mpsProject))

override fun getElement(): IMPSProject {
return project
override fun getElement(): MPSProjectAsNode {
return this
}

override fun getPropertyAccessors(): List<Pair<IPropertyReference, IPropertyAccessor<IMPSProject>>> {
override fun getPropertyAccessors(): List<Pair<IPropertyReference, IPropertyAccessor<MPSProjectAsNode>>> {
return propertyAccessors
}

override fun getReferenceAccessors(): List<Pair<IReferenceLinkReference, IReferenceAccessor<IMPSProject>>> {
override fun getReferenceAccessors(): List<Pair<IReferenceLinkReference, IReferenceAccessor<MPSProjectAsNode>>> {
return emptyList()
}

override fun getChildAccessors(): List<Pair<IChildLinkReference, IChildAccessor<IMPSProject>>> {
override fun getChildAccessors(): List<Pair<IChildLinkReference, IChildAccessor<MPSProjectAsNode>>> {
return childAccessors
}

Expand All @@ -136,7 +145,7 @@
}

override fun getNodeReference(): MPSProjectReference {
return MPSProjectReference(project)
return id
}

override fun getConcept(): IConcept {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import org.modelix.model.api.IReferenceLinkReference
import org.modelix.model.api.IWritableNode

data class MPSProjectModuleAsNode(val project: IMPSProject, val module: SModule) : MPSGenericNodeAdapter<MPSProjectModuleAsNode>() {
data class MPSProjectModuleAsNode(val projectNode: MPSProjectAsNode, val module: SModule) : MPSGenericNodeAdapter<MPSProjectModuleAsNode>() {

Check warning

Code scanning / detekt

MPSProjectModuleAsNode is missing required documentation. Warning

MPSProjectModuleAsNode is missing required documentation.

Check warning

Code scanning / detekt

The property projectNode is missing documentation. Warning

The property projectNode is missing documentation.

Check warning

Code scanning / detekt

The property module is missing documentation. Warning

The property module is missing documentation.

companion object {
private val propertyAccessors: List<Pair<IPropertyReference, IPropertyAccessor<MPSProjectModuleAsNode>>> = listOf(
Expand Down Expand Up @@ -43,6 +43,8 @@
)
}

val project: IMPSProject get() = projectNode.project

Check warning

Code scanning / detekt

The property project is missing documentation. Warning

The property project is missing documentation.

override fun getElement(): MPSProjectModuleAsNode {
return this
}
Expand All @@ -60,7 +62,7 @@
}

override fun getParent(): MPSProjectAsNode {
return MPSProjectAsNode(project)
return projectNode
}

override fun getNodeReference(): INodeReference {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ data class MPSRepositoryAsNode(@get:JvmName("getRepository_") val repository: SR
requireNotNull(sourceNode.getNode().getPropertyValue(BuiltinLanguages.MPSRepositoryConcepts.Module.id.toReference())) {
"Solution has no ID: ${sourceNode.getNode()}"
}.let { ModuleId.fromString(it) },
sourceNode.getNode().getPropertyValue(BuiltinLanguages.MPSRepositoryConcepts.Module.isReadOnly.toReference()).toBoolean(),
).let { MPSModuleAsNode(it) }
}
BuiltinLanguages.MPSRepositoryConcepts.Language.getReference() -> {
Expand Down Expand Up @@ -111,7 +112,7 @@ 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 MPSProjectAsNode.getContextProjects().map { MPSProjectAsNode(it) }
return MPSProjectAsNode.getContextProjectNodes()
}

override fun addNew(element: SRepository, index: Int, sourceNode: SpecWithResolvedConcept): IWritableNode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,23 @@

class SolutionProducer(private val myProject: IMPSProject) {

fun create(name: String, id: ModuleId): Solution {
fun create(name: String, id: ModuleId, readOnly: Boolean = false): Solution {

Check warning

Code scanning / detekt

The function create is missing documentation. Warning

The function create is missing documentation.
val basePath = checkNotNull(myProject.getBasePath()) { "Project has no base path: $myProject" }
val projectBaseDir = myProject.getFileSystem().getFile(basePath)
val solutionBaseDir = projectBaseDir.findChild("solutions").findChild(name)
return create(name, id, solutionBaseDir)
return create(name, id, solutionBaseDir, readOnly)
}

fun create(namespace: String, id: ModuleId, moduleDir: IFile): Solution {
fun create(namespace: String, id: ModuleId, moduleDir: IFile, readOnly: Boolean): Solution {

Check warning

Code scanning / detekt

The function create is missing documentation. Warning

The function create is missing documentation.
val descriptorFile = moduleDir.findChild(namespace + MPSExtentions.DOT_SOLUTION)
val descriptor: SolutionDescriptor = createSolutionDescriptor(namespace, id, descriptorFile)
val descriptor: SolutionDescriptor = createSolutionDescriptor(namespace, id, descriptorFile, readOnly)
val module = GeneralModuleFactory().instantiate(descriptor, descriptorFile) as Solution
myProject.addModule(module)
module.save()
return module
}

private fun createSolutionDescriptor(namespace: String, id: ModuleId, descriptorFile: IFile): SolutionDescriptor {
private fun createSolutionDescriptor(namespace: String, id: ModuleId, descriptorFile: IFile, readOnly: Boolean): SolutionDescriptor {
val descriptor = SolutionDescriptor()
// using outputPath instead of outputRoot for backwards compatibility
// descriptor.outputRoot = "\${module}/source_gen"
Expand All @@ -53,6 +53,7 @@

descriptor.modelRootDescriptors.add(DefaultModelRoot.createDescriptor(modelsDir.parent!!, modelsDir))
descriptor.outputPath = descriptorFile.parent!!.findChild("source_gen").path
descriptor.readOnlyStubModule(readOnly)
return descriptor
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ data class MPSModelReference(val moduleReference: MPSModuleReference?, val model
return arrayOf<String?>(moduleId, modelID, moduleName, modelName)
}

fun random() = MPSModelReference(null, randomUUID())
fun random(): MPSModelReference = MPSModelReference(null, "r:" + randomUUID())
}

override fun serialize(): String {
Expand Down
Loading
Loading