Skip to content

Commit 7df96c5

Browse files
authored
Merge pull request #957 from modelix/fix/error-no-included-modules
MODELIX-784 Clearly state that no module matched the specified conditions when exporting from MPS in the error message
2 parents b132ea5 + f83d52e commit 7df96c5

File tree

6 files changed

+95
-6
lines changed

6 files changed

+95
-6
lines changed

bulk-model-sync-gradle/src/main/kotlin/org/modelix/model/sync/bulk/gradle/tasks/ExportFromModelServer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ abstract class ExportFromModelServer : DefaultTask() {
8484
branch.runRead {
8585
val root = branch.getRootNode()
8686
logger.info("Got root node: {}", root)
87-
val outputDir = outputDir.get().asFile
87+
val outputDir = outputDir.get().asFile.toPath()
8888

8989
getIncludedModules(root).forEach {
9090
val fileName = it.getPropertyValue(BuiltinLanguages.jetbrains_mps_lang_core.INamedConcept.name)

bulk-model-sync-lib/mps-test/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ dependencies {
3434
testImplementation(project(":mps-model-adapters"))
3535
testImplementation(libs.kotlin.serialization.json)
3636
testImplementation(libs.xmlunit.matchers)
37+
testImplementation(libs.jimfs)
3738
}
3839

3940
intellij {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2024.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.modelix.model.sync.bulk.lib.test
18+
import com.google.common.jimfs.Jimfs
19+
import org.modelix.mps.model.sync.bulk.MPSBulkSynchronizer
20+
import kotlin.io.path.listDirectoryEntries
21+
import kotlin.io.path.name
22+
23+
class ExportRepositoryTest : MPSTestBase() {
24+
25+
private val fileSystem = Jimfs.newFileSystem()
26+
private val outputPath = fileSystem.getPath("/some/output/path")
27+
28+
fun `test exports module included by name (testdata oneEmptyModule)`() {
29+
MPSBulkSynchronizer.exportModulesFromRepository(mpsProject.repository, setOf("onlySolution"), emptySet(), outputPath)
30+
31+
assertEquals(listOf("onlySolution.json"), outputPath.listDirectoryEntries().map { it.name })
32+
}
33+
34+
fun `test exports module included by prefix (testdata oneEmptyModule)`() {
35+
MPSBulkSynchronizer.exportModulesFromRepository(mpsProject.repository, emptySet(), setOf("onlySol"), outputPath)
36+
37+
assertEquals(listOf("onlySolution.json"), outputPath.listDirectoryEntries().map { it.name })
38+
}
39+
40+
fun `test fail if no module is found (testdata oneEmptyModule)`() {
41+
val expectedMsg = """
42+
No module matched the inclusion criteria.
43+
[includedModules] = [someSolution]
44+
[includedModulePrefixes] = [somePrefix]
45+
""".trimIndent()
46+
47+
try {
48+
MPSBulkSynchronizer
49+
.exportModulesFromRepository(mpsProject.repository, setOf("someSolution"), setOf("somePrefix"), outputPath)
50+
fail("Exporting models should fail.")
51+
} catch (ex: IllegalArgumentException) {
52+
assertEquals(expectedMsg, ex.message)
53+
} catch (ex: Throwable) {
54+
fail("Expected IllegalArgumentException but got $ex")
55+
}
56+
}
57+
}

bulk-model-sync-lib/src/jvmMain/kotlin/org/modelix/model/sync/bulk/ModelExporter.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ import kotlinx.serialization.json.Json
2121
import kotlinx.serialization.json.encodeToStream
2222
import org.modelix.model.api.INode
2323
import org.modelix.model.data.ModelData
24-
import java.io.File
24+
import java.nio.file.Files
25+
import java.nio.file.Path
26+
import kotlin.io.path.outputStream
2527

2628
actual class ModelExporter actual constructor(private val root: INode) {
2729

@@ -31,8 +33,8 @@ actual class ModelExporter actual constructor(private val root: INode) {
3133
* @param outputFile target file of the export
3234
*/
3335
@OptIn(ExperimentalSerializationApi::class)
34-
fun export(outputFile: File) {
35-
outputFile.parentFile.mkdirs()
36+
fun export(outputFile: Path) {
37+
Files.createDirectories(outputFile.parent)
3638

3739
val modelData = ModelData(root = root.asExported())
3840
outputFile.outputStream().use { outputStream ->

bulk-model-sync-mps/src/main/kotlin/org/modelix/mps/model/sync/bulk/MPSBulkSynchronizer.kt

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import kotlinx.coroutines.runBlocking
3333
import kotlinx.serialization.ExperimentalSerializationApi
3434
import kotlinx.serialization.json.Json
3535
import kotlinx.serialization.json.decodeFromStream
36+
import org.jetbrains.annotations.VisibleForTesting
3637
import org.jetbrains.mps.openapi.model.EditableSModel
3738
import org.jetbrains.mps.openapi.module.ModelAccess
3839
import org.jetbrains.mps.openapi.module.SModule
@@ -55,6 +56,7 @@ import org.modelix.model.sync.bulk.ModelImporter
5556
import org.modelix.model.sync.bulk.ModelSynchronizer
5657
import org.modelix.model.sync.bulk.isModuleIncluded
5758
import java.io.File
59+
import java.nio.file.Path
5860
import java.util.concurrent.atomic.AtomicInteger
5961

6062
/**
@@ -91,14 +93,38 @@ object MPSBulkSynchronizer {
9193
val includedModuleNames = parseRawPropertySet(System.getProperty("modelix.mps.model.sync.bulk.output.modules"))
9294
val includedModulePrefixes =
9395
parseRawPropertySet(System.getProperty("modelix.mps.model.sync.bulk.output.modules.prefixes"))
96+
val outputPathName = System.getProperty("modelix.mps.model.sync.bulk.output.path")
97+
val outputPath = Path.of(outputPathName)
98+
exportModulesFromRepository(repository, includedModuleNames, includedModulePrefixes, outputPath)
99+
}
94100

101+
/**
102+
* Export modules that are included either by [includedModuleNames] or [includedModulePrefixes]
103+
* as files into [outputPath].
104+
*/
105+
@JvmStatic
106+
@VisibleForTesting
107+
fun exportModulesFromRepository(
108+
repository: SRepository,
109+
includedModuleNames: Set<String>,
110+
includedModulePrefixes: Set<String>,
111+
outputPath: Path,
112+
) {
95113
repository.modelAccess.runReadAction {
96114
val allModules = repository.modules
97115
val includedModules = allModules.filter {
98116
isModuleIncluded(it.moduleName!!, includedModuleNames, includedModulePrefixes)
99117
}
118+
119+
require(includedModules.isNotEmpty()) {
120+
"""
121+
No module matched the inclusion criteria.
122+
[includedModules] = $includedModuleNames
123+
[includedModulePrefixes] = $includedModulePrefixes
124+
""".trimIndent()
125+
}
126+
100127
val numIncludedModules = includedModules.count()
101-
val outputPath = System.getProperty("modelix.mps.model.sync.bulk.output.path")
102128
val counter = AtomicInteger()
103129

104130
includedModules.parallelStream().forEach { module ->
@@ -107,7 +133,7 @@ object MPSBulkSynchronizer {
107133
repository.modelAccess.runReadAction {
108134
println("Exporting module $pos of $numIncludedModules: '${module.moduleName}'")
109135
val exporter = ModelExporter(MPSModuleAsNode(module))
110-
val outputFile = File(outputPath + File.separator + module.moduleName + ".json")
136+
val outputFile = outputPath.resolve(module.moduleName + ".json")
111137
exporter.export(outputFile)
112138
println("Exported module $pos of $numIncludedModules: '${module.moduleName}'")
113139
}
@@ -162,6 +188,7 @@ object MPSBulkSynchronizer {
162188
* [getModulesToImport] is a lambda to be executed with read access in MPS.
163189
*/
164190
@JvmStatic
191+
@VisibleForTesting
165192
fun importModelsIntoRepository(
166193
repository: SRepository,
167194
rootOfImport: INode,

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,5 @@ micrometer-registry-prometheus = { group = "io.micrometer", name = "micrometer-r
128128

129129
detekt-api = { group = "io.gitlab.arturbosch.detekt", name= "detekt-api", version.ref = "detekt" }
130130
detekt-test = { group = "io.gitlab.arturbosch.detekt", name= "detekt-test", version.ref = "detekt" }
131+
132+
jimfs = { group = "com.google.jimfs", name = "jimfs", version = "1.3.0" }

0 commit comments

Comments
 (0)