From 785fa8b469dfed9a827211a88f844ec5ff7c143b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 15:11:11 +0200 Subject: [PATCH 01/44] build: prepare for publishing snapshots --- build.gradle.kts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index bd0dfaa..8578c1a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -94,25 +94,29 @@ tasks.register("setTeamCityBuildNumber") { publishing { repositories { - maven { - name = "itemisCloud" - url = uri("https://artifacts.itemis.cloud/repository/maven-mps-releases/") - if (project.hasProperty("artifacts.itemis.cloud.user") && project.hasProperty("artifacts.itemis.cloud.pw")) { + val isSnapshot = project.version.toString().endsWith("SNAPSHOT") + if (project.hasProperty("artifacts.itemis.cloud.user") && project.hasProperty("artifacts.itemis.cloud.pw")) { + maven { + name = "itemisCloud" + if (isSnapshot) { + url = uri("https://artifacts.itemis.cloud/repository/maven-mps-snapshots/") + } else { + url = uri("https://artifacts.itemis.cloud/repository/maven-mps-releases/") + } credentials { username = project.findProperty("artifacts.itemis.cloud.user") as String? password = project.findProperty("artifacts.itemis.cloud.pw") as String? } } } - if (currentBranch == "master" || currentBranch == "v1.x") { + + if (!isSnapshot && project.hasProperty("gpr.token")) { maven { name = "GitHubPackages" url = uri("https://maven.pkg.github.com/mbeddr/mps-gradle-plugin") - if(project.hasProperty("gpr.token")) { - credentials { - username = project.findProperty("gpr.user") as String? - password = project.findProperty("gpr.token") as String? - } + credentials { + username = project.findProperty("gpr.user") as String? + password = project.findProperty("gpr.token") as String? } } } From 2b2fb8872c14174e89dc01a44744d45b6002a53a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 15:11:38 +0200 Subject: [PATCH 02/44] build: set SNAPSHOT version --- build.gradle.kts | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8578c1a..fd4e56e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,3 @@ -import de.itemis.mps.gradle.GitBasedVersioning import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.KotlinVersion @@ -23,23 +22,7 @@ plugins { group = "de.itemis.mps" -val baseVersion = "3.0.0-dev" -val currentBranch : String? = GitBasedVersioning.getGitBranch() - -version = if (!project.hasProperty("useSnapshot") && - (project.hasProperty("forceCI") || project.hasProperty("teamcity")) -) { - val prefix = when (currentBranch) { - null, "", "v1.x", "HEAD", "master", "main" -> "" - else -> "$currentBranch." - } - - val suffix = ".${GitBasedVersioning.getGitCommitCount()}.${GitBasedVersioning.getGitShortCommitHash()}" - - prefix + baseVersion + suffix -} else { - "$baseVersion-SNAPSHOT" -} +version = "3.0.0-SNAPSHOT" val mpsConfiguration = configurations.create("mps") From ae969fa0b9949b69ac2405ae40820231ca0fc98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 15:12:15 +0200 Subject: [PATCH 03/44] build: remove unused 'mps' configuration --- build.gradle.kts | 2 -- gradle.lockfile | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index fd4e56e..2d8278b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -24,8 +24,6 @@ group = "de.itemis.mps" version = "3.0.0-SNAPSHOT" -val mpsConfiguration = configurations.create("mps") - repositories { mavenCentral() // For mps-build-backends, during tests diff --git a/gradle.lockfile b/gradle.lockfile index bec2bf9..1b6e38b 100644 --- a/gradle.lockfile +++ b/gradle.lockfile @@ -32,4 +32,4 @@ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClass org.jetbrains:annotations:13.0=bcv-rt-jvm-cp-resolver,compileClasspath,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,implementationDependenciesMetadata,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath org.ow2.asm:asm-tree:9.6=bcv-rt-jvm-cp-resolver org.ow2.asm:asm:9.6=bcv-rt-jvm-cp-resolver -empty=annotationProcessor,apiDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDefExtensions,mps,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDefExtensions +empty=annotationProcessor,apiDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDefExtensions,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDefExtensions From 234ed26d02da866ea858febfb2ac9c2f8886dc11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Mon, 13 Apr 2026 16:31:13 +0200 Subject: [PATCH 04/44] Remove old plugins (generate-models, modelcheck, run-migrations, download-jbr) Remove GenerateMpsProjectPlugin, ModelcheckMpsProjectPlugin, RunMigrationsMpsProjectPlugin, DownloadJbrProjectPlugin, FakeBuildNumberTask, BasePluginExtensions, and all related code. These are replaced by direct use of the @Incubating task types (MpsGenerate, MpsCheck, etc.). Co-Authored-By: Claude Opus 4.6 (1M context) --- api/mps-gradle-plugin.api | 160 -------- build.gradle.kts | 18 +- .../kotlin/de/itemis/mps/gradle/Common.kt | 109 ------ .../de/itemis/mps/gradle/ErrorMessages.kt | 18 - .../de/itemis/mps/gradle/RunAntScript.kt | 58 ++- .../itemis/mps/gradle/downloadJBR/Plugin.kt | 137 ------- .../de/itemis/mps/gradle/generate/Plugin.kt | 123 ------ .../de/itemis/mps/gradle/generate/Tasks.kt | 41 -- .../de/itemis/mps/gradle/modelcheck/Plugin.kt | 134 ------- .../itemis/mps/gradle/runmigrations/Plugin.kt | 221 ----------- .../de/itemis/mps/gradle/tasks/PluginIds.kt | 3 +- .../mps/gradle/tasks/backend_arguments.kt | 3 +- .../test/migration/RunMigrationsTest.kt | 145 +------ .../modelchecking/ModelCheckWithPluginTest.kt | 312 --------------- .../test/modelchecking/MpsCheckTaskTest.kt | 3 +- .../modelgeneration/GenerateModelsTest.kt | 363 ------------------ .../modelgeneration/MpsGenerateTaskTest.kt | 3 +- .../kotlin/test/others/JBRDownloadTest.kt | 291 -------------- 18 files changed, 32 insertions(+), 2110 deletions(-) delete mode 100644 src/main/kotlin/de/itemis/mps/gradle/ErrorMessages.kt delete mode 100644 src/main/kotlin/de/itemis/mps/gradle/downloadJBR/Plugin.kt delete mode 100644 src/main/kotlin/de/itemis/mps/gradle/generate/Plugin.kt delete mode 100644 src/main/kotlin/de/itemis/mps/gradle/generate/Tasks.kt delete mode 100644 src/main/kotlin/de/itemis/mps/gradle/modelcheck/Plugin.kt delete mode 100644 src/main/kotlin/de/itemis/mps/gradle/runmigrations/Plugin.kt delete mode 100644 src/test/kotlin/test/modelchecking/ModelCheckWithPluginTest.kt delete mode 100644 src/test/kotlin/test/modelgeneration/GenerateModelsTest.kt delete mode 100644 src/test/kotlin/test/others/JBRDownloadTest.kt diff --git a/api/mps-gradle-plugin.api b/api/mps-gradle-plugin.api index 51b6f91..330cdb3 100644 --- a/api/mps-gradle-plugin.api +++ b/api/mps-gradle-plugin.api @@ -1,31 +1,3 @@ -public class de/itemis/mps/gradle/BasePluginExtensions { - public fun (Lorg/gradle/api/model/ObjectFactory;)V - public final fun getBackendConfig ()Lorg/gradle/api/artifacts/Configuration; - public final fun getDebug ()Z - public final fun getEnvironmentKind ()Lorg/gradle/api/provider/Property; - public final fun getJavaExec ()Ljava/io/File; - public final fun getMacros ()Ljava/util/List; - public final fun getMaxHeap ()Ljava/lang/String; - public final fun getMpsConfig ()Lorg/gradle/api/artifacts/Configuration; - public final fun getMpsLocation ()Ljava/io/File; - public final fun getMpsVersion ()Ljava/lang/String; - public final fun getPluginLocation ()Ljava/io/File; - public final fun getPlugins ()Ljava/util/List; - public final fun getPluginsProperty ()Lorg/gradle/api/provider/ListProperty; - public final fun getProjectLocation ()Ljava/io/File; - public final fun setBackendConfig (Lorg/gradle/api/artifacts/Configuration;)V - public final fun setDebug (Z)V - public final fun setJavaExec (Ljava/io/File;)V - public final fun setMacros (Ljava/util/List;)V - public final fun setMaxHeap (Ljava/lang/String;)V - public final fun setMpsConfig (Lorg/gradle/api/artifacts/Configuration;)V - public final fun setMpsLocation (Ljava/io/File;)V - public final fun setMpsVersion (Ljava/lang/String;)V - public final fun setPluginLocation (Ljava/io/File;)V - public final fun setPlugins (Ljava/util/List;)V - public final fun setProjectLocation (Ljava/io/File;)V -} - public abstract class de/itemis/mps/gradle/BuildLanguages : de/itemis/mps/gradle/RunAntScript { public fun ()V } @@ -59,11 +31,6 @@ public class de/itemis/mps/gradle/BundledScripts : groovy/lang/GroovyObject { public final class de/itemis/mps/gradle/CommonKt { public static final field MPS_BUILD_BACKENDS_VERSION Ljava/lang/String; - public static final field MPS_SUPPORT_MSG Ljava/lang/String; - public static final fun argsFromBaseExtension (Lde/itemis/mps/gradle/BasePluginExtensions;)Lorg/gradle/process/CommandLineArgumentProvider; - public static final fun getMPSVersion (Lde/itemis/mps/gradle/BasePluginExtensions;)Ljava/lang/String; - public static final fun getMPSVersion (Lde/itemis/mps/gradle/BasePluginExtensions;Ljava/lang/String;)Ljava/lang/String; - public static final fun validateDefaultJvm ()V } public final class de/itemis/mps/gradle/CommonPlugin : org/gradle/api/Plugin { @@ -129,36 +96,6 @@ public class de/itemis/mps/gradle/GetMpsInBrowser : org/gradle/api/DefaultTask, public fun setVersion (Ljava/lang/String;)Ljava/lang/Object; } -public final class de/itemis/mps/gradle/Macro { - public fun (Ljava/lang/String;Ljava/lang/String;)V - public final fun component1 ()Ljava/lang/String; - public final fun component2 ()Ljava/lang/String; - public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lde/itemis/mps/gradle/Macro; - public static synthetic fun copy$default (Lde/itemis/mps/gradle/Macro;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lde/itemis/mps/gradle/Macro; - public fun equals (Ljava/lang/Object;)Z - public final fun getName ()Ljava/lang/String; - public final fun getValue ()Ljava/lang/String; - public fun hashCode ()I - public final fun setName (Ljava/lang/String;)V - public final fun setValue (Ljava/lang/String;)V - public fun toString ()Ljava/lang/String; -} - -public final class de/itemis/mps/gradle/Plugin { - public fun (Ljava/lang/String;Ljava/lang/String;)V - public final fun component1 ()Ljava/lang/String; - public final fun component2 ()Ljava/lang/String; - public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lde/itemis/mps/gradle/Plugin; - public static synthetic fun copy$default (Lde/itemis/mps/gradle/Plugin;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lde/itemis/mps/gradle/Plugin; - public fun equals (Ljava/lang/Object;)Z - public final fun getId ()Ljava/lang/String; - public final fun getPath ()Ljava/lang/String; - public fun hashCode ()I - public final fun setId (Ljava/lang/String;)V - public final fun setPath (Ljava/lang/String;)V - public fun toString ()Ljava/lang/String; -} - public class de/itemis/mps/gradle/Pom : groovy/lang/GroovyObject { public static synthetic field __$stMC Z protected synthetic fun $getStaticMetaClass ()Lgroovy/lang/MetaClass; @@ -198,17 +135,6 @@ public abstract class de/itemis/mps/gradle/TestLanguages : de/itemis/mps/gradle/ public fun ()V } -public class de/itemis/mps/gradle/downloadJBR/DownloadJbrConfiguration { - public field jbrVersion Ljava/lang/String; - public fun (Lorg/gradle/api/model/ObjectFactory;)V - public final fun getDistributionType ()Ljava/lang/String; - public final fun getDownloadDir ()Ljava/io/File; - public final fun getJbrVersion ()Ljava/lang/String; - public final fun setDistributionType (Ljava/lang/String;)V - public final fun setDownloadDir (Ljava/io/File;)V - public final fun setJbrVersion (Ljava/lang/String;)V -} - public class de/itemis/mps/gradle/downloadJBR/DownloadJbrForPlatform : org/gradle/api/DefaultTask { public fun (Lorg/gradle/api/model/ObjectFactory;Lorg/gradle/jvm/toolchain/JavaToolchainService;)V public final fun getJavaExecutable ()Ljava/io/File; @@ -219,92 +145,6 @@ public class de/itemis/mps/gradle/downloadJBR/DownloadJbrForPlatform : org/gradl public final fun setJbrDir (Ljava/io/File;)V } -public abstract class de/itemis/mps/gradle/downloadJBR/DownloadJbrProjectPlugin : org/gradle/api/Plugin { - public fun ()V - public synthetic fun apply (Ljava/lang/Object;)V - public fun apply (Lorg/gradle/api/Project;)V - protected abstract fun getExecOperations ()Lorg/gradle/process/ExecOperations; -} - -public abstract class de/itemis/mps/gradle/generate/FakeBuildNumberTask : org/gradle/api/DefaultTask { - public fun ()V - public final fun fakeBuildNumber ()V - public final fun getBuildTxt ()Lorg/gradle/api/provider/Provider; - public abstract fun getMpsDir ()Lorg/gradle/api/file/DirectoryProperty; -} - -public class de/itemis/mps/gradle/generate/GenerateMpsProjectPlugin : org/gradle/api/Plugin { - public fun ()V - public synthetic fun apply (Ljava/lang/Object;)V - public fun apply (Lorg/gradle/api/Project;)V -} - -public class de/itemis/mps/gradle/generate/GeneratePluginExtensions : de/itemis/mps/gradle/BasePluginExtensions { - public fun (Lorg/gradle/api/model/ObjectFactory;)V - public final fun getExcludeModels ()Ljava/util/List; - public final fun getExcludeModules ()Ljava/util/List; - public final fun getModels ()Ljava/util/List; - public final fun getModules ()Ljava/util/List; - public final fun getParallelGenerationThreads ()I - public final fun setExcludeModels (Ljava/util/List;)V - public final fun setExcludeModules (Ljava/util/List;)V - public final fun setModels (Ljava/util/List;)V - public final fun setModules (Ljava/util/List;)V - public final fun setParallelGenerationThreads (I)V -} - -public class de/itemis/mps/gradle/modelcheck/ModelCheckPluginExtensions : de/itemis/mps/gradle/BasePluginExtensions { - public fun (Lorg/gradle/api/model/ObjectFactory;)V - public final fun getErrorNoFail ()Z - public final fun getExcludeModels ()Ljava/util/List; - public final fun getExcludeModules ()Ljava/util/List; - public final fun getJunitFile ()Ljava/io/File; - public final fun getJunitFormat ()Ljava/lang/String; - public final fun getModels ()Ljava/util/List; - public final fun getModules ()Ljava/util/List; - public final fun getParallel ()Z - public final fun getWarningAsError ()Z - public final fun setErrorNoFail (Z)V - public final fun setExcludeModels (Ljava/util/List;)V - public final fun setExcludeModules (Ljava/util/List;)V - public final fun setJunitFile (Ljava/io/File;)V - public final fun setJunitFormat (Ljava/lang/String;)V - public final fun setModels (Ljava/util/List;)V - public final fun setModules (Ljava/util/List;)V - public final fun setParallel (Z)V - public final fun setWarningAsError (Z)V -} - -public class de/itemis/mps/gradle/modelcheck/ModelcheckMpsProjectPlugin : org/gradle/api/Plugin { - public fun ()V - public synthetic fun apply (Ljava/lang/Object;)V - public fun apply (Lorg/gradle/api/Project;)V -} - -public class de/itemis/mps/gradle/runmigrations/MigrationExecutorPluginExtensions : de/itemis/mps/gradle/BasePluginExtensions { - public fun (Lorg/gradle/api/model/ObjectFactory;)V - public final fun getForce ()Ljava/lang/Boolean; - public final fun getHaltOnDependencyError ()Ljava/lang/Boolean; - public final fun getHaltOnPrecheckFailure ()Ljava/lang/Boolean; - public final fun setForce (Ljava/lang/Boolean;)V - public final fun setHaltOnDependencyError (Ljava/lang/Boolean;)V - public final fun setHaltOnPrecheckFailure (Ljava/lang/Boolean;)V -} - -public abstract class de/itemis/mps/gradle/runmigrations/RunMigrationsMpsProjectPlugin : org/gradle/api/Plugin { - public static final field Companion Lde/itemis/mps/gradle/runmigrations/RunMigrationsMpsProjectPlugin$Companion; - public fun ()V - public synthetic fun apply (Ljava/lang/Object;)V - public fun apply (Lorg/gradle/api/Project;)V - protected abstract fun getExecOperations ()Lorg/gradle/process/ExecOperations; -} - -public final class de/itemis/mps/gradle/runmigrations/RunMigrationsMpsProjectPlugin$Companion { - public final fun getMIN_VERSION_FOR_FORCE ()Lnet/swiftzer/semver/SemVer; - public final fun getMIN_VERSION_FOR_HALT_ON_DEPENDENCY_ERROR ()Lnet/swiftzer/semver/SemVer; - public final fun getMIN_VERSION_FOR_HALT_ON_PRECHECK_FAILURE ()Lnet/swiftzer/semver/SemVer; -} - public final class de/itemis/mps/gradle/tasks/ExcludedModuleMigration { public fun (Ljava/lang/String;I)V public final fun component1 ()Ljava/lang/String; diff --git a/build.gradle.kts b/build.gradle.kts index 2d8278b..fe56dda 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -48,22 +48,8 @@ tasks.test { gradlePlugin { plugins { - register("generate-models") { - id = "generate-models" - implementationClass = "de.itemis.mps.gradle.generate.GenerateMpsProjectPlugin" - } - register("modelcheck") { - id = "modelcheck" - implementationClass = "de.itemis.mps.gradle.modelcheck.ModelcheckMpsProjectPlugin" - } - register("migrations-executor") { - id = "run-migrations" - implementationClass = "de.itemis.mps.gradle.runmigrations.RunMigrationsMpsProjectPlugin" - } - register("download-jbr") { - id = "download-jbr" - implementationClass = "de.itemis.mps.gradle.downloadJBR.DownloadJbrProjectPlugin" - } + // Plugins are provided by the common.gradle.kts precompiled script plugin. + // Task types are used directly by consumers. } } diff --git a/src/main/kotlin/de/itemis/mps/gradle/Common.kt b/src/main/kotlin/de/itemis/mps/gradle/Common.kt index 94783ce..99edbdc 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/Common.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/Common.kt @@ -1,114 +1,5 @@ package de.itemis.mps.gradle -import org.apache.log4j.Logger -import org.gradle.api.GradleException -import org.gradle.api.JavaVersion -import org.gradle.api.artifacts.Configuration -import org.gradle.api.model.ObjectFactory -import org.gradle.api.provider.ListProperty -import org.gradle.kotlin.dsl.property -import org.gradle.process.CommandLineArgumentProvider -import java.io.File -import javax.inject.Inject - -private val logger = Logger.getLogger("de.itemis.mps.gradle.common") - -const val MPS_SUPPORT_MSG = ErrorMessages.MPS_VERSION_NOT_SUPPORTED - const val MPS_BUILD_BACKENDS_VERSION = "[1.15,2.0)" // 1.15 required for --plugin-root support. -data class Plugin( - var id: String, - var path: String -) - -data class Macro( - var name: String, - var value: String -) - enum class EnvironmentKind { MPS, IDEA } - -open class BasePluginExtensions @Inject constructor(objectFactory: ObjectFactory) { - var mpsConfig: Configuration? = null - var mpsLocation: File? = null - var mpsVersion: String? = null - - /** - * The plugins to load. Backed by [pluginsProperty] which should be used instead of this property. - */ - @Deprecated("Use pluginsProperty") - var plugins: List - get() = pluginsProperty.get() - set(value) { pluginsProperty.value(value) } - - /** - * The plugins to load. - */ - val pluginsProperty: ListProperty = objectFactory.listProperty(Plugin::class.java) - - var pluginLocation: File? = null - var macros: List = emptyList() - var projectLocation: File? = null - var debug = false - var javaExec: File? = null - var backendConfig: Configuration? = null - - /** - * The environment to set up, IDEA or MPS. Default is IDEA for backwards compatibility reasons. - */ - val environmentKind = objectFactory.property(EnvironmentKind::class).convention(EnvironmentKind.IDEA) - - /** - * Maximum heap size, passed as the argument to the `-Xmx` JVM option. Example: `4G`, `512m`. - */ - var maxHeap: String? = null -} - -fun validateDefaultJvm(){ - if (JavaVersion.current() < JavaVersion.VERSION_11) logger.error("MPS requires at least Java 11 but current JVM uses ${JavaVersion.current()}, starting MPS will most probably fail!") -} - -fun argsFromBaseExtension(extensions: BasePluginExtensions): CommandLineArgumentProvider = - CommandLineArgumentProvider { - val result = mutableListOf() - - if (extensions.pluginLocation != null) { - result.add("--plugin-location=${extensions.pluginLocation!!.absolutePath}") - } - - val projectLocation = extensions.projectLocation ?: throw GradleException("No project path set") - result.add("--project=${projectLocation.absolutePath}") - - extensions.pluginsProperty.get().mapTo(result) { "--plugin=${it.id}::${it.path}" } - extensions.macros.mapTo(result) { "--macro=${it.name}::${it.value}" } - - // --environment is supported by backend 1.2 and above - result.add("--environment=${extensions.environmentKind.get().name}") - - result - } - -@Deprecated("Use getMPSVersion(extensionName)", replaceWith = ReplaceWith("getMPSVersion(this.javaClass.name)")) -fun BasePluginExtensions.getMPSVersion(): String = getMPSVersion(this.javaClass.name) - -/** - * [extensionName]: extension name, for diagnostics. - */ -fun BasePluginExtensions.getMPSVersion(extensionName: String): String { - // If the user supplies explicit mpsVersion, we use it. - if (mpsVersion != null) return mpsVersion!! - - val mpsConfig = mpsConfig - if (mpsConfig != null) { - // If the user supplies a configuration, we use it to detect MPS version. - return mpsConfig.resolvedConfiguration.firstLevelModuleDependencies - .find { it.moduleGroup == "com.jetbrains" && it.moduleName == "mps" } - ?.moduleVersion - ?: throw GradleException(ErrorMessages.couldNotDetermineMpsVersionFromConfiguration(mpsConfig) - ) - } - - // Otherwise, the version has to be provided explicitly. - throw GradleException(ErrorMessages.mustSetVersionWhenNoMpsConfiguration(extensionName)) -} diff --git a/src/main/kotlin/de/itemis/mps/gradle/ErrorMessages.kt b/src/main/kotlin/de/itemis/mps/gradle/ErrorMessages.kt deleted file mode 100644 index 15142fb..0000000 --- a/src/main/kotlin/de/itemis/mps/gradle/ErrorMessages.kt +++ /dev/null @@ -1,18 +0,0 @@ -package de.itemis.mps.gradle - -import org.gradle.api.artifacts.Configuration -import java.io.File - -internal object ErrorMessages { - const val MPS_VERSION_NOT_SUPPORTED = "This version of mps-gradle-plugin only supports MPS 2020.1 and above. Please use version 1.4 with an older version of MPS." - - internal fun noMpsProjectIn(dir: File): String = "Directory does not contain an MPS project: $dir" - - internal fun couldNotDetermineMpsVersionFromConfiguration(mpsConfig: Configuration) = - "Could not determine MPS version from configuration ${mpsConfig.name} (configuration must contain com.jetbrains:mps dependency)." - - internal fun mustSetConfigOrLocation(extensionName: String) = "Either mpsConfig or mpsLocation needs to specified for extension $extensionName." - internal fun mustSetVersionWhenNoMpsConfiguration(extensionName: String) = - "Could not determine MPS version because mpsConfiguration was not specified. Set mpsVersion of $extensionName" + - " extension explicitly." -} diff --git a/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt b/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt index 25815c3..9feab89 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt @@ -1,7 +1,6 @@ package de.itemis.mps.gradle; import org.gradle.api.DefaultTask -import org.gradle.api.Project import org.gradle.api.file.FileCollection import org.gradle.api.logging.LogLevel import org.gradle.api.tasks.Input @@ -9,7 +8,6 @@ import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.Optional import org.gradle.api.tasks.TaskAction import org.gradle.process.ExecOperations -import java.io.File import javax.inject.Inject abstract class RunAntScript : DefaultTask() { @@ -61,7 +59,7 @@ abstract class RunAntScript : DefaultTask() { } } - if(logging.level != null && logging.level != LogLevel.LIFECYCLE && !allArgs.any { it.startsWith("-Dmps.ant.log=") }) { + if (logging.level != null && logging.level != LogLevel.LIFECYCLE && !allArgs.any { it.startsWith("-Dmps.ant.log=") }) { allArgs += "-Dmps.ant.log=${logging.level.toString().lowercase()}" } @@ -71,8 +69,29 @@ abstract class RunAntScript : DefaultTask() { val targets = if (incremental) { targets - "clean" } else { targets } - project.runAnt(execOperations, executable, project.rootDir, allArgs + "-buildfile" + project.file(script).toString() + targets, - includeDefaultClasspath, scriptClasspath) + val effectiveExecutable = executable ?: project.findProperty("itemis.mps.gradle.ant.defaultJavaExecutable") + + execOperations.javaexec { + if (effectiveExecutable != null) { + executable(effectiveExecutable) + } + + mainClass.set("org.apache.tools.ant.launch.Launcher") + workingDir = project.rootDir + + if (includeDefaultClasspath) { + val defaultClasspath = project.findProperty("itemis.mps.gradle.ant.defaultScriptClasspath") + if (defaultClasspath != null) { + classpath(defaultClasspath) + } + } + + if (scriptClasspath != null) { + classpath(scriptClasspath) + } + + args(allArgs + "-buildfile" + project.file(script).toString() + targets) + } } } @@ -87,32 +106,3 @@ abstract class BuildLanguages : RunAntScript() { targets = listOf("clean", "generate", "assemble", "check") } } - -internal fun Project.runAnt(execOperations: ExecOperations, executable: Any?, workingDir: File, args: List, - includeDefaultClasspath: Boolean = true, - scriptClasspath: Any? = null -) { - val effectiveExecutable = executable ?: project.findProperty("itemis.mps.gradle.ant.defaultJavaExecutable") - - execOperations.javaexec { - if (effectiveExecutable != null) { - executable(effectiveExecutable) - } - - mainClass.set("org.apache.tools.ant.launch.Launcher") - this@javaexec.workingDir = workingDir - - if (includeDefaultClasspath) { - val defaultClasspath = project.findProperty("itemis.mps.gradle.ant.defaultScriptClasspath") - if (defaultClasspath != null) { - classpath(defaultClasspath) - } - } - - if (scriptClasspath != null) { - classpath(scriptClasspath) - } - - args(args) - } -} diff --git a/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/Plugin.kt b/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/Plugin.kt deleted file mode 100644 index 957c6b6..0000000 --- a/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/Plugin.kt +++ /dev/null @@ -1,137 +0,0 @@ -package de.itemis.mps.gradle.downloadJBR - -import org.apache.tools.ant.taskdefs.condition.Os -import org.gradle.api.GradleException -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.model.ObjectFactory -import org.gradle.process.ExecOperations -import java.io.File -import javax.inject.Inject - -open class DownloadJbrConfiguration @Inject constructor(objects: ObjectFactory) { - lateinit var jbrVersion: String - var distributionType : String? = null - internal val downloadDirProperty: DirectoryProperty = objects.directoryProperty() - - var downloadDir: File? - get() = downloadDirProperty.get().asFile - set(value) { - downloadDirProperty.set(value) - } -} - -abstract class DownloadJbrProjectPlugin : Plugin { - - @get:Inject - protected abstract val execOperations: ExecOperations - - override fun apply(project: Project) { - project.run { - - val extension = extensions.create("downloadJbr", DownloadJbrConfiguration::class.java) - extension.downloadDirProperty.convention(layout.buildDirectory.dir("jbrDownload")) - - val configuration = configurations.detachedConfiguration() - configuration.dependencies.addLater(provider { project.dependencies.create(dependencyString(extension)) }) - - val extractJbr = tasks.register("extractJbr") { - inputs.files(configuration).skipWhenEmpty() - outputs.dir(extension.downloadDirProperty) - - doLast { - if (Os.isFamily(Os.FAMILY_UNIX)) { - // Use Unix utilities to properly deal with symlinks - delete(extension.downloadDirProperty) - val downloadDir = mkdir(extension.downloadDirProperty) - - execOperations.exec { - commandLine("tar", "-xzf", configuration.singleFile.absolutePath) - workingDir = downloadDir - } - - if (downloadDir.listFiles { _, name -> name.startsWith("jbr_") || name.startsWith("jbr-") }!!.any()) { - execOperations.exec { - commandLine("sh", "-c", "mv jbr* jbr") - workingDir = downloadDir - } - } - - execOperations.exec { - commandLine("chmod", "-R", "u+w", ".") - workingDir = downloadDir - } - } else { - // On Windows we don't worry about symlinks nor file modes. - sync { - from({ tarTree(configuration.singleFile) }) - into(extension.downloadDirProperty) - includeEmptyDirs = false - eachFile { - permissions { user { write = true } } - } - filesMatching("jbr_*/**") { - path = path.replace("jbr_(.*?)/(.*)".toRegex(), "jbr/$2") - } - } - } - } - } - - tasks.register("downloadJbr", DownloadJbrForPlatform::class.java) { - dependsOn(extractJbr) - group = "Build" - description = "Downloads the JetBrains Runtime for the current platform and extracts it." - - jbrDirProperty.set(extension.downloadDirProperty.dir( - if (Os.isFamily(Os.FAMILY_MAC)) "jbr/Contents/Home" - else "jbr" - )) - javaExecutableProperty.set(jbrDirProperty.file(if (Os.isFamily(Os.FAMILY_WINDOWS)) "bin/java.exe" else "bin/java")) - } - } - } - - private fun dependencyString(extension: DownloadJbrConfiguration): String { - val version = extension.jbrVersion - // from version 10 on the jbr distribution type is replaced with jbr_jcef - // jbr_jcef is the distribution used to start a normal desktop ide and should include everything - // required for running tests. While a little bit larger than jbr_nomod it should cause the least - // surprises when using it as a default. - // see https://github.com/mbeddr/build.publish.jdk/commit/10bbf7d177336179ca189fc8bb4c1262029c69da - val distributionType = - if (extension.distributionType != null) { - extension.distributionType - } else if (Regex("""11_0_[0-9][^0-9]""").find(version) != null) { - "jbr" - } else { - "jbr_jcef" - } - - val cpuArch = when(System.getProperty ("os.arch")) { - "aarch64" -> "aarch64" - "amd64" -> "x64" - "x86_64" -> "x64" - else -> throw GradleException("Unsupported CPU Architecture: ${System.getProperty ("os.arch")}! Please open a bug at https://github.com/mbeddr/mps-gradle-plugin with details about your operating system and CPU.") - - } - - val dependencyString = when { - Os.isFamily(Os.FAMILY_MAC) -> { - "com.jetbrains.jdk:$distributionType:$version:osx-$cpuArch@tgz" - } - Os.isFamily(Os.FAMILY_WINDOWS) -> { - "com.jetbrains.jdk:$distributionType:$version:windows-$cpuArch@tgz" - } - Os.isFamily(Os.FAMILY_UNIX) -> { - "com.jetbrains.jdk:$distributionType:$version:linux-$cpuArch@tgz" - } - else -> { - throw GradleException("Unsupported platform! Please open a bug at https://github.com/mbeddr/mps-gradle-plugin with details about your operating system.") - } - } - - return dependencyString - } -} diff --git a/src/main/kotlin/de/itemis/mps/gradle/generate/Plugin.kt b/src/main/kotlin/de/itemis/mps/gradle/generate/Plugin.kt deleted file mode 100644 index 5b936ca..0000000 --- a/src/main/kotlin/de/itemis/mps/gradle/generate/Plugin.kt +++ /dev/null @@ -1,123 +0,0 @@ -package de.itemis.mps.gradle.generate - -import de.itemis.mps.gradle.* -import de.itemis.mps.gradle.launcher.MpsBackendBuilder -import de.itemis.mps.gradle.launcher.MpsBackendLauncher -import org.apache.tools.ant.taskdefs.Java -import org.gradle.api.GradleException -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.artifacts.Configuration -import org.gradle.api.model.ObjectFactory -import org.gradle.api.provider.Provider -import org.gradle.api.tasks.Copy -import org.gradle.api.tasks.JavaExec -import org.gradle.jvm.toolchain.JavaLauncher -import org.gradle.kotlin.dsl.newInstance -import org.gradle.process.CommandLineArgumentProvider -import java.io.File - -open class GeneratePluginExtensions(objectFactory: ObjectFactory): BasePluginExtensions(objectFactory){ - var models: List = emptyList() - var modules: List = emptyList() - var excludeModels: List = emptyList() - var excludeModules: List = emptyList() - var parallelGenerationThreads: Int = 0 -} - -open class GenerateMpsProjectPlugin : Plugin { - - override fun apply(project: Project) { - project.run { - val extensionName = "generate" - val extension = extensions.create(extensionName, GeneratePluginExtensions::class.java) - val generate = tasks.register("generate", JavaExec::class.java) - val fake = tasks.register("fakeBuildNumber", FakeBuildNumberTask::class.java) - - afterEvaluate { - val mpsVersion = extension.getMPSVersion(extensionName) - - val genConfig = extension.backendConfig ?: createDetachedBackendConfig(project) - - if(mpsVersion.substring(0..3).toInt() < 2020) { - throw GradleException(MPS_SUPPORT_MSG) - } - - val mpsLocation = extension.mpsLocation ?: layout.buildDirectory.dir("mps").get().asFile - val resolveMps = if (extension.mpsConfig != null) { - tasks.register("resolveMpsForGeneration", Copy::class.java) { - from({ extension.mpsConfig!!.resolve().map(::zipTree) }) - into(mpsLocation) - } - } else if (extension.mpsLocation != null) { - tasks.register("resolveMpsForGeneration") - } else { - throw GradleException(ErrorMessages.mustSetConfigOrLocation(extensionName)) - } - - /* - * The problem here is is that for some reason the ApplicationInfo isn't initialised properly. - * That causes PluginManagerCore.BUILD_NUMBER to be null. - * In this case the PluginManagerCore resorts to BuildNumber.currentVersion() which finally - * calls into BuildNumber.fromFile(). - * - * This behaviour allows us to place a build.txt in the root of the home path (see PathManager.getHomePath()). - * The file is then used to load the build number. - * - * TODO: Since MPS 2018.2 a newer version of the platform allows to get a similar behaviour via setting idea.plugins.compatible.build property. - * - */ - fake.configure { - mpsDir.set(mpsLocation) - dependsOn(resolveMps) - } - - generate.configure { - val backendBuilder: MpsBackendBuilder = project.objects.newInstance(MpsBackendBuilder::class) - backendBuilder.withMpsHome(mpsLocation).withMpsVersion(mpsVersion).configure(this) - - dependsOn(fake) - - argumentProviders.add(argsFromBaseExtension(extension)) - argumentProviders.add(CommandLineArgumentProvider { - mutableListOf().apply { - addAll(extension.models.map { "--model=$it" }) - addAll(extension.modules.map { "--module=$it" }) - addAll(extension.excludeModels.map { "--exclude-model=$it" }) - addAll(extension.excludeModules.map { "--exclude-module=$it" }) - add("--parallel-generation-threads=${extension.parallelGenerationThreads}") - } - }) - - if (extension.javaExec != null) { - javaLauncher.set(null as JavaLauncher?) - executable(extension.javaExec!!) - } else { - validateDefaultJvm() - } - - group = "build" - description = "Generates models in the project" - classpath(fileTree(File(mpsLocation, "/lib")).include("**/*.jar")) - // add only minimal number of plugins jars that are required by the generate code - // (to avoid conflicts with plugin classloader if custom configured plugins are loaded) - // git4idea: has to be on classpath as bundled plugin to be loaded (since 2019.3) - classpath(fileTree(File(mpsLocation, "/plugins")).include("git4idea/**/*.jar")) - classpath(genConfig) - debug = extension.debug - mainClass.set("de.itemis.mps.gradle.generate.MainKt") - - if (extension.maxHeap != null) { - maxHeapSize = extension.maxHeap!! - } - } - } - } - } - - private fun createDetachedBackendConfig(project: Project): Configuration { - val dep = project.dependencies.create("de.itemis.mps.build-backends:execute-generators:${MPS_BUILD_BACKENDS_VERSION}") - val genConfig = project.configurations.detachedConfiguration(dep) - return genConfig - } -} diff --git a/src/main/kotlin/de/itemis/mps/gradle/generate/Tasks.kt b/src/main/kotlin/de/itemis/mps/gradle/generate/Tasks.kt deleted file mode 100644 index 81982bd..0000000 --- a/src/main/kotlin/de/itemis/mps/gradle/generate/Tasks.kt +++ /dev/null @@ -1,41 +0,0 @@ -package de.itemis.mps.gradle.generate - -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.file.RegularFile -import org.gradle.api.provider.Provider -import org.gradle.api.tasks.InputDirectory -import org.gradle.api.tasks.Optional -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction -import java.io.PrintWriter -import java.util.* - - -abstract class FakeBuildNumberTask : DefaultTask() { - - @get:InputDirectory - abstract val mpsDir: DirectoryProperty - - @TaskAction - fun fakeBuildNumber() { - val buildProperties = mpsDir.get().asFile.resolve("build.properties") - - if (!buildProperties.isFile) throw GradleException("can't locate build.properties file in MPS directory") - - val props = Properties() - props.load(buildProperties.inputStream()) - val buildNumber = props.getProperty("mps.build.number") - val buildTxt: Provider = this.getBuildTxt() - val writer = PrintWriter(buildTxt.get().asFile.outputStream()) - - writer.write(buildNumber) - writer.close() - } - - @OutputFile - fun getBuildTxt(): Provider { - return mpsDir.file("build.txt") - } -} diff --git a/src/main/kotlin/de/itemis/mps/gradle/modelcheck/Plugin.kt b/src/main/kotlin/de/itemis/mps/gradle/modelcheck/Plugin.kt deleted file mode 100644 index 1cedf05..0000000 --- a/src/main/kotlin/de/itemis/mps/gradle/modelcheck/Plugin.kt +++ /dev/null @@ -1,134 +0,0 @@ -package de.itemis.mps.gradle.modelcheck - -import de.itemis.mps.gradle.* -import de.itemis.mps.gradle.launcher.MpsBackendBuilder -import de.itemis.mps.gradle.launcher.MpsBackendLauncher -import org.gradle.api.GradleException -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.artifacts.Configuration -import org.gradle.api.model.ObjectFactory -import org.gradle.api.tasks.Copy -import org.gradle.api.tasks.JavaExec -import org.gradle.kotlin.dsl.newInstance -import org.gradle.process.CommandLineArgumentProvider -import java.io.File -import javax.inject.Inject - -open class ModelCheckPluginExtensions(objectFactory: ObjectFactory) : BasePluginExtensions(objectFactory) { - var models: List = emptyList() - var modules: List = emptyList() - var excludeModels: List = emptyList() - var excludeModules: List = emptyList() - var warningAsError = false - var errorNoFail = false - var junitFile: File? = null - var junitFormat: String? = null - var parallel: Boolean = false -} - -open class ModelcheckMpsProjectPlugin : Plugin { - override fun apply(project: Project) { - project.run { - val extensionName = "modelcheck" - val extension = extensions.create(extensionName, ModelCheckPluginExtensions::class.java) - val checkmodels = tasks.register("checkmodels", JavaExec::class.java) - - afterEvaluate { - val mpsVersion = extension.getMPSVersion(extensionName) - - val genConfig = extension.backendConfig ?: createDetachedBackendConfig(project) - - if(mpsVersion.substring(0..3).toInt() < 2020) { - throw GradleException(MPS_SUPPORT_MSG) - } - - val mpsLocation = extension.mpsLocation ?: layout.buildDirectory.dir("mps").get().asFile - val resolveMps = if (extension.mpsConfig != null) { - tasks.register("resolveMpsForModelcheck", Copy::class.java) { - from({ extension.mpsConfig!!.resolve().map(::zipTree) }) - into(mpsLocation) - } - } else if (extension.mpsLocation != null) { - tasks.register("resolveMpsForModelcheck") - } else { - throw GradleException(ErrorMessages.mustSetConfigOrLocation(extensionName)) - } - - checkmodels.configure { - val backendBuilder: MpsBackendBuilder = project.objects.newInstance(MpsBackendBuilder::class) - backendBuilder.withMpsHome(mpsLocation).withMpsVersion(mpsVersion).configure(this) - - dependsOn(resolveMps) - - argumentProviders.add(argsFromBaseExtension(extension)) - argumentProviders.add(CommandLineArgumentProvider { - val args = mutableListOf() - args.addAll(extension.models.map { "--model=$it" }) - args.addAll(extension.modules.map { "--module=$it" }) - args.addAll(extension.excludeModels.map { "--exclude-model=$it" }) - args.addAll(extension.excludeModules.map { "--exclude-module=$it" }) - - if (extension.warningAsError) { - args.add("--warning-as-error") - } - - if (extension.errorNoFail) { - args.add("--error-no-fail") - } - - if (extension.junitFile != null) { - args.add("--result-file=${extension.junitFile!!.absolutePath}") - } - - if (extension.junitFormat != null) { - args.add("--result-format=${extension.junitFormat}") - } - - if (extension.parallel) { - args.add("--parallel") - } - args - }) - - if (extension.javaExec != null) { - javaLauncher.set(null) - executable(extension.javaExec!!) - } else { - validateDefaultJvm() - } - - group = "test" - description = "Check models in the project" - if (extension.maxHeap != null) { - maxHeapSize = extension.maxHeap!! - } - classpath(fileTree(File(mpsLocation, "/lib")).include("**/*.jar")) - // add only minimal number of plugins jars that are required by the modelcheck code - // (to avoid conflicts with plugin classloader if custom configured plugins are loaded) - // mps-httpsupport: we need it to print the node url to the console. - // mps-modelchecker: contains used UnresolvedReferencesChecker - // git4idea: has to be on classpath as bundled plugin to be loaded (since 2019.3) - classpath( - fileTree(File(mpsLocation, "/plugins")).include( - "mps-modelchecker/**/*.jar", - "mps-httpsupport/**/*.jar", - "git4idea/**/*.jar" - ) - ) - classpath(genConfig) - debug = extension.debug - mainClass.set("de.itemis.mps.gradle.modelcheck.MainKt") - } - } - - } - } - - private fun createDetachedBackendConfig(project: Project): Configuration { - val dep = project.dependencies.create("de.itemis.mps.build-backends:modelcheck:${MPS_BUILD_BACKENDS_VERSION}") - val genConfig = project.configurations.detachedConfiguration(dep) - return genConfig - } - -} diff --git a/src/main/kotlin/de/itemis/mps/gradle/runmigrations/Plugin.kt b/src/main/kotlin/de/itemis/mps/gradle/runmigrations/Plugin.kt deleted file mode 100644 index e5de486..0000000 --- a/src/main/kotlin/de/itemis/mps/gradle/runmigrations/Plugin.kt +++ /dev/null @@ -1,221 +0,0 @@ -package de.itemis.mps.gradle.runmigrations - -import de.itemis.mps.gradle.BasePluginExtensions -import de.itemis.mps.gradle.ErrorMessages -import de.itemis.mps.gradle.getMPSVersion -import de.itemis.mps.gradle.runAnt -import groovy.xml.MarkupBuilder -import net.swiftzer.semver.SemVer -import org.gradle.api.GradleException -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.model.ObjectFactory -import org.gradle.api.tasks.Copy -import org.gradle.kotlin.dsl.withGroovyBuilder -import org.gradle.process.ExecOperations -import java.io.File -import javax.inject.Inject - -open class MigrationExecutorPluginExtensions @Inject constructor(of: ObjectFactory) : BasePluginExtensions(of) { - /** - * (Since MPS 2021.1) Whether to halt if a pre-check has failed. Note that to ignore the check for migrated - * dependencies the [haltOnDependencyError] option must be set to `false` as well. - */ - var haltOnPrecheckFailure: Boolean? = null - - /** - * (Since MPS 2021.3.4) Whether to halt when a non-migrated dependency is discovered. - */ - var haltOnDependencyError: Boolean? = null - - /** - * (Since MPS 2021.3) Whether to force a migration even if the project directory contains `.allow-pending-migrations` file. - */ - var force: Boolean? = null -} - -@Suppress("unused") -abstract class RunMigrationsMpsProjectPlugin : Plugin { - - @get:Inject - protected abstract val execOperations: ExecOperations - - companion object { - val MIN_VERSION_FOR_HALT_ON_PRECHECK_FAILURE = SemVer(2021, 1) - val MIN_VERSION_FOR_HALT_ON_DEPENDENCY_ERROR = SemVer(2021, 3, 4) - val MIN_VERSION_FOR_FORCE = SemVer(2021, 3) - } - - override fun apply(project: Project) { - project.run { - val extensionName = "runMigrations" - val extension = extensions.create(extensionName, MigrationExecutorPluginExtensions::class.java) - - tasks.register("runMigrations") - - afterEvaluate { - val projectLocation = extension.projectLocation ?: throw GradleException("No project path set") - if (!file(projectLocation).exists()) { - throw GradleException("The path to the project doesn't exist: $projectLocation") - } - - val mpsVersion = extension.getMPSVersion(extensionName) - val parsedMPSVersion = SemVer.parse(mpsVersion) - - if (extension.force != null && parsedMPSVersion < MIN_VERSION_FOR_FORCE) { - throw GradleException("The force migration flag is only supported for MPS version $MIN_VERSION_FOR_FORCE and higher.") - } - - if (extension.haltOnPrecheckFailure != null && parsedMPSVersion < MIN_VERSION_FOR_HALT_ON_PRECHECK_FAILURE) { - throw GradleException("The 'do not halt on pre-check failure' option is only supported for MPS version $MIN_VERSION_FOR_HALT_ON_PRECHECK_FAILURE and higher.") - } - - if (extension.haltOnDependencyError != null && parsedMPSVersion < MIN_VERSION_FOR_HALT_ON_DEPENDENCY_ERROR) { - throw GradleException("The 'do not halt on dependency error' option is only supported for MPS version $MIN_VERSION_FOR_HALT_ON_DEPENDENCY_ERROR and higher.") - } - - val mpsLocation = extension.mpsLocation ?: layout.buildDirectory.dir("mps").get().asFile - val resolveMps = if (extension.mpsConfig != null) { - tasks.register("resolveMpsForMigrations", Copy::class.java) { - from({ extension.mpsConfig!!.resolve().map(::zipTree) }) - into(mpsLocation) - } - } else if (extension.mpsLocation != null) { - tasks.register("resolveMpsForMigrations") - } else { - throw GradleException(ErrorMessages.mustSetConfigOrLocation(extensionName)) - } - - tasks.named("runMigrations") { - dependsOn(resolveMps) - doLast { - if (!mpsLocation.isDirectory) { - throw GradleException("Specified MPS location does not exist or is not a directory: $mpsLocation") - } - - // Clean temporary dir to help avoid strange errors - temporaryDir.listFiles()?.forEach { it.deleteRecursively() } - - val buildFile = temporaryDir.resolve("build.xml") - buildFile.printWriter().use { - MarkupBuilder(it).withGroovyBuilder { - "project" { - "path"("id" to "path.mps.ant.path") { - // The different MPS versions need different jars. Let's just keep it simple and include all jars. - "fileset"("dir" to "$mpsLocation/lib", "includes" to "**/*.jar") - } - "taskdef"( - "resource" to "jetbrains/mps/build/ant/antlib.xml", - "classpathref" to "path.mps.ant.path" - ) - - val argsToMigrate = mutableListOf>().run { - add("project" to projectLocation) - add("mpsHome" to mpsLocation) - - extension.force?.let { add("force" to it) } - extension.haltOnPrecheckFailure?.let { add("haltOnPrecheckFailure" to it) } - extension.haltOnDependencyError?.let { add("haltOnDependencyError" to it) } - - toTypedArray() - } - - "migrate"(*argsToMigrate) { - "macro"("name" to "mps_home", "path" to mpsLocation) - - extension.macros.forEach { - "macro"("name" to it.name, "path" to it.value) - } - - "jvmargs" { - "arg"("value" to "-Didea.log.config.file=log.xml") - "arg"("value" to "-ea") - - if (extension.maxHeap != null) { - "arg"("value" to "-Xmx${extension.maxHeap}") - } - - if (extension.debug) { - "arg"("value" to "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005") - } - - "arg"("value" to "--add-opens=java.base/java.io=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.base/java.lang=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.base/java.net=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.base/java.nio=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.base/java.nio.charset=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.base/java.text=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.base/java.time=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.base/java.util=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.base/java.util.concurrent=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.base/jdk.internal.vm=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.base/sun.security.ssl=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.base/sun.security.util=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/java.awt=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/java.awt.dnd.peer=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/java.awt.event=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/java.awt.image=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/java.awt.peer=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/javax.swing=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/javax.swing.plaf.basic=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/javax.swing.text.html=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/sun.awt.datatransfer=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/sun.awt.image=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/sun.awt=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/sun.font=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/sun.java2d=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/sun.swing=ALL-UNNAMED") - "arg"("value" to "--add-opens=jdk.attach/sun.tools.attach=ALL-UNNAMED") - "arg"("value" to "--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED") - "arg"("value" to "--add-opens=jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED") - "arg"("value" to "--add-opens=jdk.jdi/com.sun.tools.jdi=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/com.apple.laf=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/com.apple.eawt=ALL-UNNAMED") - "arg"("value" to "--add-opens=java.desktop/com.apple.eawt.event=ALL-UNNAMED") - } - - extension.pluginsProperty.get().forEach { - // Same handling as in mps-build-backends - if (File(it.path).isAbsolute) { - "plugin"("path" to it.path, "id" to it.id) - } else if (extension.pluginLocation != null && File( - extension.pluginLocation, - it.path - ).exists() - ) { - "plugin"( - "path" to File(extension.pluginLocation, it.path), - "id" to it.id - ) - } else { - "plugin"( - "path" to mpsLocation.resolve("plugins").resolve(it.path), - "id" to it.id - ) - } - } - } - } - } - } - - val classpath = project.fileTree(mpsLocation.resolve("lib")) { - include("ant/lib/*.jar") - include("*.jar") - builtBy(resolveMps) - } - - runAnt( - execOperations, extension.javaExec, temporaryDir, args = listOf(), - includeDefaultClasspath = false, - scriptClasspath = classpath - ) - } - } - } - } - } -} diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/PluginIds.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/PluginIds.kt index 4b08b1b..d5334dc 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/tasks/PluginIds.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/PluginIds.kt @@ -1,6 +1,5 @@ package de.itemis.mps.gradle.tasks -import de.itemis.mps.gradle.Plugin import org.slf4j.LoggerFactory import org.w3c.dom.Document import java.io.File @@ -15,6 +14,8 @@ import java.util.jar.JarFile import javax.xml.parsers.DocumentBuilder import javax.xml.parsers.DocumentBuilderFactory +internal data class Plugin(var id: String, var path: String) + internal val logger = LoggerFactory.getLogger("de.itemis.mps.gradle.tasks.PluginIds")!! internal fun findPluginsRecursively(root: File): List = mutableListOf().apply { diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt index 47cf84c..e2621d9 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt @@ -1,6 +1,5 @@ package de.itemis.mps.gradle.tasks -import de.itemis.mps.gradle.ErrorMessages import org.gradle.api.GradleException import org.gradle.api.file.Directory import org.gradle.api.file.FileCollection @@ -13,7 +12,7 @@ internal fun checkProjectLocation(projectLocation: Provider("downloadJbr").javaExecutable - } - - tasks.register("verify") { - dependsOn("downloadJbr") - doLast { - val launcherMatches = - tasks.getByName("checkmodels").javaLauncher.get().executablePath.asFile == - tasks.getByName("downloadJbr").javaExecutable - println("javaLauncher matches: " + launcherMatches) - } - } - """.trimIndent() - ) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("--stacktrace", "verify") - .withPluginClasspath() - .build() - - Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":verify")?.outcome) - - // When javaExec is explicitly set, the launcher should match the downloaded executable - Assert.assertTrue("javaLauncher should match explicitly set executable", - result.output.contains("javaLauncher matches: true")) - } - - @Test - fun `check model fails if errors are found`() { - extractProject("test-project-with-errors") - - settingsFile.writeText(settingsBoilerplate()) - - buildFile.writeText( - buildScriptBoilerplate("2022.2.2") + - """ - modelcheck { - projectLocation = file("${mpsTestPrjLocation.toPath()}") - mpsConfig = mps - junitFile = file("${junitFile.absolutePath}") - } - """.trimIndent() - ) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("checkmodels") - .withPluginClasspath() - .buildAndFail() - Assert.assertEquals(TaskOutcome.FAILED, result.task(":checkmodels")?.outcome) - Assert.assertTrue(junitFile.exists()) - } - - @Test - fun `check model works with latest MPS and excluded models`() { - extractProject("test-project-with-errors") - - settingsFile.writeText(settingsBoilerplate()) - - buildFile.writeText( - buildScriptBoilerplate("2022.2.2") + - """ - modelcheck { - projectLocation = file("${mpsTestPrjLocation.toPath()}") - mpsConfig = mps - junitFile = file("${junitFile.absolutePath}") - excludeModels = listOf("my.solution.with.errors.java") - } - """.trimIndent() - ) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("checkmodels") - .withPluginClasspath() - .build() - Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":checkmodels")?.outcome) - Assert.assertTrue(junitFile.exists()) - } - - @Test - fun `check model fails with unsupported MPS`() { - extractProject("test-project") - - settingsFile.writeText(settingsBoilerplate()) - - buildFile.writeText( - buildScriptBoilerplate("2019.3.7") + - """ - modelcheck { - projectLocation = file("${mpsTestPrjLocation.toPath()}") - mpsConfig = mps - junitFile = file("${junitFile.absolutePath}") - - } - """.trimIndent() - ) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("checkmodels") - .withPluginClasspath() - .buildAndFail() - MatcherAssert.assertThat(result.output, CoreMatchers.containsString(ErrorMessages.MPS_VERSION_NOT_SUPPORTED)) - } - - @Test - fun `check model works with set MPS version and path`() { - extractProject("test-project") - - settingsFile.writeText(settingsBoilerplate()) - - buildFile.writeText( - buildScriptBoilerplate("2022.2.2") + - """ - modelcheck { - projectLocation = file("${mpsTestPrjLocation.toPath()}") - mpsVersion = "2020.2.2" - mpsLocation = file(".") - junitFile = file("${junitFile.absolutePath}") - } - """.trimIndent() - ) - - GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments() - .withPluginClasspath() - .build() - } - - @Test - fun `check model fails with set MPS invalid version and path`() { - extractProject("test-project") - - settingsFile.writeText(settingsBoilerplate()) - - buildFile.writeText( - buildScriptBoilerplate("2022.2.2") + - """ - modelcheck { - projectLocation = file("${mpsTestPrjLocation.toPath()}") - mpsVersion = "2019.2.2" - mpsLocation = file(".") - junitFile = file("${junitFile.absolutePath}") - } - """.trimIndent() - ) - - GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments() - .withPluginClasspath() - .buildAndFail() - } - - @Test - fun `check model fails with only MPS version set`() { - extractProject("test-project") - - settingsFile.writeText(settingsBoilerplate()) - - buildFile.writeText( - buildScriptBoilerplate("2022.2.2") + - """ - modelcheck { - projectLocation = file("${mpsTestPrjLocation.toPath()}") - mpsVersion = "2022.2.2" - junitFile = file("${junitFile.absolutePath}") - } - """.trimIndent() - ) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments() - .withPluginClasspath() - .buildAndFail() - - MatcherAssert.assertThat(result.output, CoreMatchers.containsString(ErrorMessages.mustSetConfigOrLocation("modelcheck"))) - } - - @Test - fun `check model fails with only MPS path set`() { - settingsFile.writeText(settingsBoilerplate()) - - buildFile.writeText( - buildScriptBoilerplate("2022.2.2") + - """ - modelcheck { - projectLocation = file("${mpsTestPrjLocation.toPath()}") - mpsLocation = file(".") - junitFile = file("${junitFile.absolutePath}") - } - """.trimIndent() - ) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments() - .withPluginClasspath() - .buildAndFail() - - MatcherAssert.assertThat(result.output, CoreMatchers.containsString( - ErrorMessages.mustSetVersionWhenNoMpsConfiguration("modelcheck"))) - } -} diff --git a/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt b/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt index 0fe95d0..0a74419 100644 --- a/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt +++ b/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt @@ -1,6 +1,5 @@ package test.modelchecking -import de.itemis.mps.gradle.ErrorMessages import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.TaskOutcome import org.hamcrest.CoreMatchers.containsString @@ -65,7 +64,7 @@ class MpsCheckTaskTest { val result = gradleRunner().withArguments("checkProject").buildAndFail() Assert.assertEquals(TaskOutcome.FAILED, result.task(":checkProject")?.outcome) - assertThat(result.output, containsString(ErrorMessages.noMpsProjectIn(testProjectDir.root.canonicalFile))) + assertThat(result.output, containsString("Directory does not contain an MPS project: ${testProjectDir.root.canonicalFile}")) } @Test diff --git a/src/test/kotlin/test/modelgeneration/GenerateModelsTest.kt b/src/test/kotlin/test/modelgeneration/GenerateModelsTest.kt deleted file mode 100644 index b27284a..0000000 --- a/src/test/kotlin/test/modelgeneration/GenerateModelsTest.kt +++ /dev/null @@ -1,363 +0,0 @@ -package test.modelgeneration - -import de.itemis.mps.gradle.ErrorMessages -import org.gradle.testkit.runner.GradleRunner -import org.gradle.testkit.runner.TaskOutcome -import org.hamcrest.CoreMatchers -import org.hamcrest.MatcherAssert -import org.junit.* -import org.junit.rules.TemporaryFolder -import support.extractTestProject -import java.io.File - -class GenerateModelsTest { - @Rule - @JvmField - val testProjectDir: TemporaryFolder = TemporaryFolder() - private lateinit var settingsFile: File - private lateinit var buildFile: File - private lateinit var cp: List - private lateinit var mpsTestPrjLocation: File - - - @Before - fun setup() { - settingsFile = testProjectDir.newFile("settings.gradle.kts") - buildFile = testProjectDir.newFile("build.gradle.kts") - mpsTestPrjLocation = testProjectDir.newFolder("mps-prj") - extractTestProject("test-project", mpsTestPrjLocation) - } - - @Test - fun `generate works with latest MPS in MPS environment`() { - settingsFile.writeText( - """ - rootProject.name = "hello-world" - """.trimIndent() - ) - - buildFile.writeText( - """ - import java.net.URI - import de.itemis.mps.gradle.EnvironmentKind - - plugins { - id("generate-models") - } - - repositories { - mavenCentral() - maven { - url = URI("https://artifacts.itemis.cloud/repository/maven-mps") - } - } - - val mps = configurations.create("mps") - - dependencies { - mps("com.jetbrains:mps:2021.3.1") - } - - generate { - projectLocation = file("${mpsTestPrjLocation.toPath()}") - mpsConfig = mps - environmentKind.set(EnvironmentKind.MPS) - } - """.trimIndent() - ) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("generate") - .withPluginClasspath() - .build() - Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":generate")?.outcome) - } - @Test - fun `generate fails with unsupported MPS`() { - settingsFile.writeText( - """ - rootProject.name = "hello-world" - """.trimIndent() - ) - - buildFile.writeText( - """ - import java.net.URI - - plugins { - id("generate-models") - } - - repositories { - mavenCentral() - maven { - url = URI("https://artifacts.itemis.cloud/repository/maven-mps") - } - } - - val mps = configurations.create("mps") - - dependencies { - mps("com.jetbrains:mps:2019.3.7") - } - - generate { - projectLocation = file("${mpsTestPrjLocation.toPath()}") - mpsConfig = mps - } - """.trimIndent() - ) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("generate") - .withPluginClasspath() - .buildAndFail() - - MatcherAssert.assertThat(result.output, CoreMatchers.containsString(ErrorMessages.MPS_VERSION_NOT_SUPPORTED)) - } - @Test - fun `generate works with set MPS version and path`() { - settingsFile.writeText( - """ - rootProject.name = "hello-world" - """.trimIndent() - ) - - val mpsFolder = testProjectDir.newFolder("mps") - - buildFile.writeText( - """ - import java.net.URI - - plugins { - id("generate-models") - } - - repositories { - mavenCentral() - maven { - url = URI("https://artifacts.itemis.cloud/repository/maven-mps") - } - } - - val mps = configurations.create("mps") - - dependencies { - mps("com.jetbrains:mps:2020.3.3") - } - - val resolveMps by tasks.registering(Sync::class) { - from({ project.zipTree(mps.singleFile) }) - into("$mpsFolder") - } - - tasks.named("fakeBuildNumber") { - dependsOn(resolveMps) - } - - generate { - projectLocation = file("${mpsTestPrjLocation.toPath()}") - mpsVersion = "2020.2.2" - mpsLocation = file("$mpsFolder") - } - """.trimIndent() - ) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("resolveMps", "generate") - .withPluginClasspath() - .build() - - Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":generate")?.outcome) - } - - @Test - fun `generate fails with set MPS invalid version and path`() { - settingsFile.writeText( - """ - rootProject.name = "hello-world" - """.trimIndent() - ) - - buildFile.writeText( - """ - import java.net.URI - - plugins { - id("generate-models") - } - - repositories { - mavenCentral() - maven { - url = URI("https://artifacts.itemis.cloud/repository/maven-mps") - } - } - - val mps = configurations.create("mps") - - dependencies { - mps("com.jetbrains:mps:2020.3.3") - } - - generate { - projectLocation = file("${mpsTestPrjLocation.toPath()}") - mpsVersion = "2019.2.2" - mpsLocation = file(".") - } - """.trimIndent() - ) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments() - .withPluginClasspath() - .buildAndFail() - - MatcherAssert.assertThat(result.output, CoreMatchers.containsString(ErrorMessages.MPS_VERSION_NOT_SUPPORTED)) - - } - @Test - fun `generate fails with only MPS version set`() { - settingsFile.writeText( - """ - rootProject.name = "hello-world" - """.trimIndent() - ) - - buildFile.writeText( - """ - import java.net.URI - - plugins { - id("generate-models") - } - - repositories { - mavenCentral() - maven { - url = URI("https://artifacts.itemis.cloud/repository/maven-mps") - } - } - - val mps = configurations.create("mps") - - dependencies { - mps("com.jetbrains:mps:2020.3.3") - } - - generate { - projectLocation = file("${mpsTestPrjLocation.toPath()}") - mpsVersion = "2020.2.2" - } - """.trimIndent() - ) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments() - .withPluginClasspath() - .buildAndFail() - MatcherAssert.assertThat(result.output, CoreMatchers.containsString(ErrorMessages.mustSetConfigOrLocation("generate"))) - } - @Test - fun `generate fails with only MPS path set`() { - settingsFile.writeText( - """ - rootProject.name = "hello-world" - """.trimIndent() - ) - - buildFile.writeText( - """ - import java.net.URI - - plugins { - id("generate-models") - } - - repositories { - mavenCentral() - maven { - url = URI("https://artifacts.itemis.cloud/repository/maven-mps") - } - } - - val mps = configurations.create("mps") - - dependencies { - mps("com.jetbrains:mps:2020.3.3") - } - - generate { - projectLocation = file("${mpsTestPrjLocation.toPath()}") - mpsLocation = file(".") - } - """.trimIndent() - ) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments() - .withPluginClasspath() - .buildAndFail() - MatcherAssert.assertThat(result.output, CoreMatchers.containsString(ErrorMessages.mustSetVersionWhenNoMpsConfiguration("generate"))) - } - - @Test - fun `explicit javaExec`() { - buildFile.writeText( - """ - import de.itemis.mps.gradle.downloadJBR.DownloadJbrForPlatform - - plugins { - id("generate-models") - id("download-jbr") - } - - downloadJbr { - jbrVersion = "17.0.6-b469.82" - } - - repositories { - mavenCentral() - maven("https://artifacts.itemis.cloud/repository/maven-mps") - } - - generate { - projectLocation = projectDir - mpsLocation = file("build/mps") - mpsVersion = "2022.2.2" - javaExec = tasks.getByName("downloadJbr").javaExecutable - } - - tasks.register("verify") { - dependsOn("downloadJbr") - doLast { - val launcherMatches = - tasks.getByName("generate").javaLauncher.get().executablePath.asFile == - tasks.getByName("downloadJbr").javaExecutable - println("javaLauncher matches: " + launcherMatches) - } - } - """.trimIndent() - ) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("--stacktrace", "verify") - .withPluginClasspath() - .build() - - Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":verify")?.outcome) - - // When javaExec is explicitly set, the launcher should match the downloaded executable - Assert.assertTrue("javaLauncher should match explicitly set executable", - result.output.contains("javaLauncher matches: true")) - } - - -} diff --git a/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt b/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt index df46136..7eff8c9 100644 --- a/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt +++ b/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt @@ -1,6 +1,5 @@ package test.modelgeneration -import de.itemis.mps.gradle.ErrorMessages import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.TaskOutcome import org.hamcrest.CoreMatchers.containsString @@ -64,7 +63,7 @@ class MpsGenerateTaskTest { val result = gradleRunner().withArguments("generateProject").buildAndFail() Assert.assertEquals(TaskOutcome.FAILED, result.task(":generateProject")?.outcome) - assertThat(result.output, containsString(ErrorMessages.noMpsProjectIn(testProjectDir.root.canonicalFile))) + assertThat(result.output, containsString("Directory does not contain an MPS project: ${testProjectDir.root.canonicalFile}")) } @Test diff --git a/src/test/kotlin/test/others/JBRDownloadTest.kt b/src/test/kotlin/test/others/JBRDownloadTest.kt deleted file mode 100644 index af28474..0000000 --- a/src/test/kotlin/test/others/JBRDownloadTest.kt +++ /dev/null @@ -1,291 +0,0 @@ -package test.others - -import org.gradle.testkit.runner.GradleRunner -import org.gradle.testkit.runner.TaskOutcome -import org.hamcrest.CoreMatchers.containsString -import org.hamcrest.MatcherAssert.assertThat -import org.junit.Assert -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.rules.TemporaryFolder -import java.io.File - -class JBRDownloadTest { - - val JBR_VERSION = "11_0_10-b1341.41" - - @Rule - @JvmField - val testProjectDir: TemporaryFolder = TemporaryFolder() - private lateinit var settingsFile: File - private lateinit var buildFile: File - - @Before - fun setup() { - settingsFile = testProjectDir.newFile("settings.gradle.kts") - buildFile = testProjectDir.newFile("build.gradle.kts") - } - - @Test - fun `download with download dir`() { - settingsFile.writeText(""" - rootProject.name = "hello-world" - """.trimIndent()) - - buildFile.writeText(""" - import java.net.URI - - plugins { - id("download-jbr") - } - - repositories { - mavenCentral() - maven { - url = URI("https://artifacts.itemis.cloud/repository/maven-mps") - } - } - - downloadJbr { - jbrVersion = "$JBR_VERSION" - downloadDir = file("jbrdl") - } - """.trimIndent()) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("downloadJbr") - .withPluginClasspath() - .build() - Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":downloadJbr")?.outcome) - Assert.assertTrue(File(testProjectDir.root, "jbrdl").exists()) - } - - @Test - fun `download without download dir`() { - settingsFile.writeText(""" - rootProject.name = "hello-world" - """.trimIndent()) - - buildFile.writeText(""" - import java.net.URI - - plugins { - id("download-jbr") - } - - repositories { - mavenCentral() - maven { - url = URI("https://artifacts.itemis.cloud/repository/maven-mps") - } - } - - downloadJbr { - jbrVersion = "$JBR_VERSION" - } - """.trimIndent()) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("downloadJbr") - .withPluginClasspath() - .build() - Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":downloadJbr")?.outcome) - Assert.assertTrue(File(testProjectDir.root, "build/jbrDownload").exists()) - } - - @Test - fun `download new version without distribution type`() { - settingsFile.writeText(""" - rootProject.name = "hello-world" - """.trimIndent()) - - buildFile.writeText(""" - import java.net.URI - - plugins { - id("download-jbr") - } - - repositories { - mavenCentral() - maven { - url = URI("https://artifacts.itemis.cloud/repository/maven-mps") - } - } - - downloadJbr { - jbrVersion = "$JBR_VERSION" - } - """.trimIndent()) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("downloadJbr") - .withPluginClasspath() - .build() - Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":downloadJbr")?.outcome) - Assert.assertTrue(File(testProjectDir.root, "build/jbrDownload").exists()) - } - - @Test - fun `download new version with distribution type`() { - settingsFile.writeText(""" - rootProject.name = "hello-world" - """.trimIndent()) - - buildFile.writeText(""" - import java.net.URI - - plugins { - id("download-jbr") - } - - repositories { - mavenCentral() - maven { - url = URI("https://artifacts.itemis.cloud/repository/maven-mps") - } - } - - downloadJbr { - jbrVersion = "$JBR_VERSION" - distributionType = "jbr_nomod" - } - """.trimIndent()) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("downloadJbr") - .withPluginClasspath() - .build() - Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":downloadJbr")?.outcome) - Assert.assertTrue(File(testProjectDir.root, "build/jbrDownload").exists()) - } - - @Test - fun `executed downloaded java`() { - settingsFile.writeText(""" - rootProject.name = "hello-world" - """.trimIndent()) - - buildFile.writeText(""" - import java.net.URI - - plugins { - id("download-jbr") - } - - repositories { - mavenCentral() - maven { - url = URI("https://artifacts.itemis.cloud/repository/maven-mps") - } - } - - downloadJbr { - jbrVersion = "$JBR_VERSION" - } - tasks.register("exec") { - dependsOn(tasks.getByName("downloadJbr", de.itemis.mps.gradle.downloadJBR.DownloadJbrForPlatform::class)) - executable = tasks.getByName("downloadJbr", de.itemis.mps.gradle.downloadJBR.DownloadJbrForPlatform::class).javaExecutable.absolutePath - args("--version") - } - """.trimIndent()) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("exec") - .withPluginClasspath() - .build() - Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":exec")?.outcome) - } - - @Test - fun `executed downloaded java using JavaLauncher`() { - settingsFile.writeText(""" - rootProject.name = "hello-world" - """.trimIndent()) - - buildFile.writeText(""" - import java.net.URI - import de.itemis.mps.gradle.downloadJBR.DownloadJbrForPlatform - - plugins { - id("download-jbr") - } - - repositories { - mavenCentral() - maven { - url = URI("https://artifacts.itemis.cloud/repository/maven-mps") - } - } - - downloadJbr { - jbrVersion = "$JBR_VERSION" - } - - val downloadJbrTask = tasks.named("downloadJbr", DownloadJbrForPlatform::class) - - tasks.register("exec") { - dependsOn(downloadJbrTask) - javaLauncher.set(downloadJbrTask.flatMap { it.javaLauncher }) - jvmArgs("--version") - - // Main class will be ignored due to --version but has to be provided - mainClass.set("ignored") - } - """.trimIndent()) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("exec") - .withPluginClasspath() - .build() - Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":exec")?.outcome) - assertThat(result.output, containsString("OpenJDK Runtime Environment JBR")) - } - - @Test - fun `use JavaLauncher with Gradle 8_13`() { - buildFile.writeText(""" - import de.itemis.mps.gradle.downloadJBR.DownloadJbrForPlatform - - plugins { - id("download-jbr") - } - - repositories { - mavenCentral() - maven("https://artifacts.itemis.cloud/repository/maven-mps") - } - - downloadJbr { - jbrVersion = "$JBR_VERSION" - } - - val downloadJbrTask = tasks.named("downloadJbr", DownloadJbrForPlatform::class) - - tasks.register("exec") { - dependsOn(downloadJbrTask) - javaLauncher.set(downloadJbrTask.flatMap { it.javaLauncher }) - jvmArgs("--version") - - // Main class will be ignored due to --version but has to be provided - mainClass.set("ignored") - } - """.trimIndent()) - - val result = GradleRunner.create() - .withProjectDir(testProjectDir.root) - .withArguments("exec") - .withGradleVersion("8.13") - .withPluginClasspath() - .build() - Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":exec")?.outcome) - assertThat(result.output, containsString("OpenJDK Runtime Environment JBR")) - } -} From d2e6805a84f30bdb1e52d06056eb54a081352723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Mon, 13 Apr 2026 16:52:24 +0200 Subject: [PATCH 05/44] Restore ErrorMessages object Keep ErrorMessages.noMpsProjectIn() instead of inlining the message. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/main/kotlin/de/itemis/mps/gradle/ErrorMessages.kt | 7 +++++++ .../kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt | 3 ++- src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt | 3 ++- .../kotlin/test/modelgeneration/MpsGenerateTaskTest.kt | 3 ++- 4 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 src/main/kotlin/de/itemis/mps/gradle/ErrorMessages.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/ErrorMessages.kt b/src/main/kotlin/de/itemis/mps/gradle/ErrorMessages.kt new file mode 100644 index 0000000..418e360 --- /dev/null +++ b/src/main/kotlin/de/itemis/mps/gradle/ErrorMessages.kt @@ -0,0 +1,7 @@ +package de.itemis.mps.gradle + +import java.io.File + +internal object ErrorMessages { + internal fun noMpsProjectIn(dir: File): String = "Directory does not contain an MPS project: $dir" +} diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt index e2621d9..47cf84c 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt @@ -1,5 +1,6 @@ package de.itemis.mps.gradle.tasks +import de.itemis.mps.gradle.ErrorMessages import org.gradle.api.GradleException import org.gradle.api.file.Directory import org.gradle.api.file.FileCollection @@ -12,7 +13,7 @@ internal fun checkProjectLocation(projectLocation: Provider Date: Mon, 13 Apr 2026 16:53:04 +0200 Subject: [PATCH 06/44] Define MpsTask and MpsProjectTask interfaces MpsTask provides mpsHome and javaLauncher for any task that touches an MPS installation. MpsProjectTask adds mpsVersion, projectLocation, pluginRoots, folderMacros, and logLevel for tasks that operate on MPS projects. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../itemis/mps/gradle/tasks/MpsProjectTask.kt | 52 +++++++++++++++++++ .../de/itemis/mps/gradle/tasks/MpsTask.kt | 23 ++++++++ 2 files changed, 75 insertions(+) create mode 100644 src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt create mode 100644 src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt new file mode 100644 index 0000000..868b542 --- /dev/null +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt @@ -0,0 +1,52 @@ +package de.itemis.mps.gradle.tasks + +import org.gradle.api.Incubating +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.Directory +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.logging.LogLevel +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Property + +/** + * A Gradle task that operates on one or more MPS projects. + * + * Use [org.gradle.api.tasks.TaskCollection.withType] to configure all MPS project tasks at once: + * + * ```kotlin + * tasks.withType().configureEach { + * mpsHome.set(layout.projectDirectory.dir("mps")) + * projectLocation.set(layout.projectDirectory.dir("my-mps-project")) + * pluginRoots.from(layout.projectDirectory.dir("plugins")) + * } + * ``` + */ +@Incubating +interface MpsProjectTask : MpsTask { + /** + * The MPS version string (e.g. "2021.3.3"). Detected automatically from [mpsHome] if not set explicitly. + */ + val mpsVersion: Property + + /** + * The MPS project directory. Convention: the Gradle project directory (but no convention is set on + * multi-project tasks like MpsMigrate and Remigrate, so that the mutual exclusivity check with + * [projectLocations][MpsMigrate.projectLocations] works correctly). + */ + val projectLocation: DirectoryProperty + + /** + * Root directories containing MPS plugins to load. + */ + val pluginRoots: ConfigurableFileCollection + + /** + * Folder macros (path variables) to pass to MPS. Keys are macro names, values are directories. + */ + val folderMacros: MapProperty + + /** + * Log level for the MPS backend process. + */ + val logLevel: Property +} diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt new file mode 100644 index 0000000..f54b806 --- /dev/null +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt @@ -0,0 +1,23 @@ +package de.itemis.mps.gradle.tasks + +import org.gradle.api.Incubating +import org.gradle.api.Task +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.jvm.toolchain.JavaLauncher + +/** + * A Gradle task that operates on an MPS installation. + */ +@Incubating +interface MpsTask : Task { + /** + * The MPS installation directory. + */ + val mpsHome: DirectoryProperty + + /** + * The Java launcher to use for running MPS. Each MPS version requires a specific Java version. + */ + val javaLauncher: Property +} From e27396c90a43d95f84f991ea5d9df60fe82af47a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Mon, 13 Apr 2026 16:58:58 +0200 Subject: [PATCH 07/44] Implement MpsProjectTask on MpsGenerate, remove varMacros Also remove javaLauncher from MpsTask interface to avoid inherited platform declaration clash with JavaExec.getJavaLauncher() (Kotlin sees the Java method's type argument as platform-nullable, conflicting with the non-null Kotlin property declaration). Co-Authored-By: Claude Opus 4.6 (1M context) --- .../de/itemis/mps/gradle/tasks/MpsGenerate.kt | 22 ++++++++----------- .../de/itemis/mps/gradle/tasks/MpsTask.kt | 7 ------ 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt index d310802..d79b2f4 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt @@ -23,36 +23,33 @@ import org.gradle.process.CommandLineArgumentProvider @CacheableTask @Incubating -abstract class MpsGenerate : JavaExec() { +abstract class MpsGenerate : JavaExec(), MpsProjectTask { @get:Input - val logLevel: Property = objectFactory.property().convention(project.gradle.startParameter.logLevel) + override val logLevel: Property = objectFactory.property().convention(project.gradle.startParameter.logLevel) - @get:Internal("covered by mpsVersion, classpath") - val mpsHome: DirectoryProperty = objectFactory.directoryProperty() + @get:Internal("covered by mpsVersion and classpath") + override val mpsHome: DirectoryProperty = objectFactory.directoryProperty() @get:Input @get:Optional - val mpsVersion: Property = objectFactory.property() + override val mpsVersion: Property = objectFactory.property() .convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) - @get:Internal("only modules and models matter, covered by #sources") - val projectLocation: DirectoryProperty = + @get:Internal("covered by sources") + override val projectLocation: DirectoryProperty = objectFactory.directoryProperty().convention(project.layout.projectDirectory) @get:Classpath - val pluginRoots: ConfigurableFileCollection = objectFactory.fileCollection() + override val pluginRoots: ConfigurableFileCollection = objectFactory.fileCollection() @get:Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") - val folderMacros: MapProperty = objectFactory.mapProperty() + override val folderMacros: MapProperty = objectFactory.mapProperty() @get:Input val environmentKind: Property = objectFactory.property() .convention(EnvironmentKind.MPS) - @get:Input - val varMacros: MapProperty = objectFactory.mapProperty() - @get:Input val models: ListProperty = objectFactory.listProperty() @@ -105,7 +102,6 @@ abstract class MpsGenerate : JavaExec() { addPluginRoots(result, pluginRoots) addFolderMacros(result, folderMacros) - addVarMacros(result, varMacros) result.add("--environment=${environmentKind.get()}") diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt index f54b806..f2f366e 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt @@ -3,8 +3,6 @@ package de.itemis.mps.gradle.tasks import org.gradle.api.Incubating import org.gradle.api.Task import org.gradle.api.file.DirectoryProperty -import org.gradle.api.provider.Property -import org.gradle.jvm.toolchain.JavaLauncher /** * A Gradle task that operates on an MPS installation. @@ -15,9 +13,4 @@ interface MpsTask : Task { * The MPS installation directory. */ val mpsHome: DirectoryProperty - - /** - * The Java launcher to use for running MPS. Each MPS version requires a specific Java version. - */ - val javaLauncher: Property } From df7d914a2aad84f648b52ebb3227bc6b79c408ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Mon, 13 Apr 2026 17:02:53 +0200 Subject: [PATCH 08/44] Implement MpsProjectTask on MpsCheck Change pluginRoots from SetProperty to ConfigurableFileCollection. Remove varMacros. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../de/itemis/mps/gradle/tasks/MpsCheck.kt | 31 +++++++++---------- .../test/modelchecking/MpsCheckTaskTest.kt | 2 +- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt index b4a3091..91a261f 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt @@ -5,43 +5,43 @@ import de.itemis.mps.gradle.TaskGroups import de.itemis.mps.gradle.launcher.MpsBackendBuilder import de.itemis.mps.gradle.launcher.MpsVersionDetection import org.gradle.api.Incubating -import org.gradle.api.file.* +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.Directory +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.FileTree +import org.gradle.api.file.RegularFileProperty import org.gradle.api.logging.LogLevel import org.gradle.api.provider.ListProperty import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property -import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.* import org.gradle.kotlin.dsl.* import org.gradle.process.CommandLineArgumentProvider @CacheableTask @Incubating -abstract class MpsCheck : JavaExec(), VerificationTask { +abstract class MpsCheck : JavaExec(), VerificationTask, MpsProjectTask { @get:Input - val logLevel: Property = objectFactory.property().convention(project.gradle.startParameter.logLevel) + override val logLevel: Property = objectFactory.property().convention(project.gradle.startParameter.logLevel) - @get:Internal("covered by mpsVersion, classpath") - val mpsHome: DirectoryProperty = objectFactory.directoryProperty() + @get:Internal("covered by mpsVersion and classpath") + override val mpsHome: DirectoryProperty = objectFactory.directoryProperty() @get:Input @get:Optional - val mpsVersion: Property = objectFactory.property() + override val mpsVersion: Property = objectFactory.property() .convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) - @get:Internal("only modules and models matter, covered by #sources") - val projectLocation: DirectoryProperty = + @get:Internal("covered by sources") + override val projectLocation: DirectoryProperty = objectFactory.directoryProperty().convention(project.layout.projectDirectory) @get:Classpath - val pluginRoots: SetProperty = objectFactory.setProperty() + override val pluginRoots: ConfigurableFileCollection = objectFactory.fileCollection() @get:Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") - val folderMacros: MapProperty = objectFactory.mapProperty() - - @get:Input - val varMacros: MapProperty = objectFactory.mapProperty() + override val folderMacros: MapProperty = objectFactory.mapProperty() @get:Input val models: ListProperty = objectFactory.listProperty() @@ -101,9 +101,8 @@ abstract class MpsCheck : JavaExec(), VerificationTask { result.add("--project=${projectLocation.get().asFile}") - addPluginRoots(result, pluginRoots.get()) + addPluginRoots(result, pluginRoots) addFolderMacros(result, folderMacros) - addVarMacros(result, varMacros) // Only a limited subset of checkers is registered in MPS environment, IDEA environment is necessary for // proper checking. diff --git a/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt b/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt index 0fe95d0..75dba67 100644 --- a/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt +++ b/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt @@ -82,7 +82,7 @@ class MpsCheckTaskTest { mpsHome.set(layout.dir(resolveMps.map { it.destinationDir })) projectLocation.set(file("mps-prj")) junitFile.set(layout.buildDirectory.file("output.xml")) - pluginRoots.add(layout.dir(resolveMps.map { File(it.destinationDir, "plugins/mps-console") })) + pluginRoots.from(resolveMps.map { File(it.destinationDir, "plugins/mps-console") }) } """.trimIndent()) From 105a1b8f668c884280ec879768e1d86de9edd816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Mon, 13 Apr 2026 17:05:22 +0200 Subject: [PATCH 09/44] Implement MpsProjectTask on MpsExecute Change pluginRoots from SetProperty to ConfigurableFileCollection. Replace macros: MapProperty with folderMacros: MapProperty. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../de/itemis/mps/gradle/tasks/MpsExecute.kt | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt index dbcc0d7..23fc00c 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt @@ -11,7 +11,6 @@ import org.gradle.api.logging.LogLevel import org.gradle.api.provider.ListProperty import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property -import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.* import org.gradle.kotlin.dsl.newInstance import org.gradle.work.DisableCachingByDefault @@ -19,25 +18,26 @@ import org.gradle.work.DisableCachingByDefault @DisableCachingByDefault(because = "calls arbitrary user code") @Incubating -abstract class MpsExecute : JavaExec() { +abstract class MpsExecute : JavaExec(), MpsProjectTask { @get:Input - abstract val logLevel: Property + abstract override val logLevel: Property - @get:Internal - abstract val mpsHome: DirectoryProperty + @get:Internal("covered by mpsVersion and classpath") + abstract override val mpsHome: DirectoryProperty - @get:Internal - abstract val mpsVersion: Property + @get:Input + @get:Optional + abstract override val mpsVersion: Property - @get:Internal - abstract val projectLocation: DirectoryProperty + @get:Internal("covered by sources") + abstract override val projectLocation: DirectoryProperty @get:Classpath - abstract val pluginRoots: SetProperty + abstract override val pluginRoots: ConfigurableFileCollection - @get:Internal - abstract val macros: MapProperty + @get:Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") + abstract override val folderMacros: MapProperty @get:Internal abstract val module: Property @@ -68,8 +68,8 @@ abstract class MpsExecute : JavaExec() { mutableListOf().apply { add("--project=${projectLocation.get().asFile}") - addPluginRoots(this, pluginRoots.get()) - addVarMacros(this, macros) + addPluginRoots(this, pluginRoots) + addFolderMacros(this, folderMacros) add("--module=${module.get()}") add("--class=${className.get()}") From 32bfb50e232e9c6f938d998cd73cad0fc69a4a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Mon, 13 Apr 2026 17:09:09 +0200 Subject: [PATCH 10/44] Implement MpsProjectTask on MpsMigrate Add projectLocation from interface. Rename projectDirectories to projectLocations (mutually exclusive with projectLocation). Remove javaExecutable in favor of javaLauncher from MpsTask. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../de/itemis/mps/gradle/tasks/MpsMigrate.kt | 57 ++++++++++++------- .../test/migration/RunMigrationsTest.kt | 2 +- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt index 1019fe3..30bfb9a 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt @@ -4,10 +4,11 @@ import de.itemis.mps.gradle.TaskGroups import de.itemis.mps.gradle.launcher.MpsVersionDetection import groovy.xml.MarkupBuilder import org.gradle.api.DefaultTask +import org.gradle.api.GradleException import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.Directory import org.gradle.api.file.DirectoryProperty -import org.gradle.api.file.RegularFileProperty +import org.gradle.api.file.FileCollection import org.gradle.api.logging.LogLevel import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.ListProperty @@ -26,19 +27,19 @@ import javax.inject.Inject @UntrackedTask(because = "Operates 'in place'") abstract class MpsMigrate @Inject constructor( - objectFactory: ObjectFactory, + private val objectFactory: ObjectFactory, providerFactory: ProviderFactory -) : DefaultTask() { +) : DefaultTask(), MpsProjectTask { @get:Input - val logLevel: Property = objectFactory.property().convention(project.gradle.startParameter.logLevel) + override val logLevel: Property = objectFactory.property().convention(project.gradle.startParameter.logLevel) - @get:Internal - val mpsHome: DirectoryProperty = objectFactory.directoryProperty() + @get:Internal("covered by mpsVersion and classpath") + override val mpsHome: DirectoryProperty = objectFactory.directoryProperty() @get:Input @get:Optional - val mpsVersion: Property = objectFactory.property() + override val mpsVersion: Property = objectFactory.property() .convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) /** @@ -57,15 +58,17 @@ abstract class MpsMigrate @Inject constructor( val haltOnDependencyError: Property = objectFactory.property() @get:Internal("covered by allProjectFiles") - val projectDirectories: ConfigurableFileCollection = objectFactory.fileCollection() + override val projectLocation: DirectoryProperty = objectFactory.directoryProperty() + + @get:Internal("covered by allProjectFiles") + val projectLocations: ConfigurableFileCollection = objectFactory.fileCollection() @get:InputFiles @get:IgnoreEmptyDirectories @get:SkipWhenEmpty - protected val allProjectFiles = providerFactory.provider { projectDirectories.flatMap { objectFactory.fileTree().from(it) } } - - @get:Internal - val javaExecutable: RegularFileProperty = objectFactory.fileProperty() + protected val allProjectFiles = providerFactory.provider { + effectiveProjectLocations().flatMap { objectFactory.fileTree().from(it) } + } @get:Nested @get:Optional @@ -82,10 +85,10 @@ abstract class MpsMigrate @Inject constructor( val maxHeapSize: Property = objectFactory.property() @get:Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") - val folderMacros: MapProperty = objectFactory.mapProperty() + override val folderMacros: MapProperty = objectFactory.mapProperty() @get:Classpath - val pluginRoots: ConfigurableFileCollection = objectFactory.fileCollection() + override val pluginRoots: ConfigurableFileCollection = objectFactory.fileCollection() @get:Inject protected abstract val execOperations: ExecOperations @@ -94,21 +97,35 @@ abstract class MpsMigrate @Inject constructor( group = TaskGroups.MIGRATION } + private fun effectiveProjectLocations(): FileCollection { + val hasMultiple = !projectLocations.isEmpty + val hasSingle = projectLocation.isPresent + if (hasMultiple && hasSingle) { + throw GradleException("Cannot set both projectLocation and projectLocations. Use one or the other.") + } + if (!hasMultiple && !hasSingle) { + throw GradleException("Must set either projectLocation or projectLocations.") + } + return if (hasMultiple) projectLocations else objectFactory.fileCollection().from(projectLocation) + } + @TaskAction fun execute() { // When MPS detects that files have changed externally then instead of updating the VFS cache it complains. // Cleaning temporary directory helps avoid this. cleanTemporaryDir() + val effectiveLocations = effectiveProjectLocations() + val buildFile = temporaryDir.resolve("build.xml") - writeBuildFile(buildFile) + writeBuildFile(buildFile, effectiveLocations) val mpsAntClasspath = mpsHome.asFileTree.matching { include("lib/ant/lib/*.jar") include("lib/*.jar") } - for(dir in projectDirectories) { + for (dir in effectiveLocations) { checkProjectLocation(dir) } @@ -116,7 +133,7 @@ abstract class MpsMigrate @Inject constructor( mainClass.set("org.apache.tools.ant.launch.Launcher") workingDir = temporaryDir classpath = mpsAntClasspath - val executableCandidate = javaExecutable.orElse(javaLauncher.map { it.executablePath }).orNull?.toString() + val executableCandidate = javaLauncher.orNull?.executablePath?.asFile?.toString() if (executableCandidate != null) { executable = executableCandidate } @@ -128,7 +145,7 @@ abstract class MpsMigrate @Inject constructor( temporaryDir.listFiles()?.forEach { it.deleteRecursively() } } - private fun writeBuildFile(buildFile: File) { + private fun writeBuildFile(buildFile: File, effectiveLocations: FileCollection) { buildFile.printWriter().use { writer -> MarkupBuilder(writer).withGroovyBuilder { "project" { @@ -157,12 +174,12 @@ abstract class MpsMigrate @Inject constructor( } val folderMacrosValue = folderMacros.get() - val allLibraries = projectDirectories + val allLibraries = effectiveLocations .flatMap { readLibraries(it, folderMacrosValue::get) } .toSortedSet() "migrate"(*argsToMigrate) { - projectDirectories.forEach { + effectiveLocations.forEach { "project"("path" to it) } diff --git a/src/test/kotlin/test/migration/RunMigrationsTest.kt b/src/test/kotlin/test/migration/RunMigrationsTest.kt index 5f1ac80..777dc7e 100644 --- a/src/test/kotlin/test/migration/RunMigrationsTest.kt +++ b/src/test/kotlin/test/migration/RunMigrationsTest.kt @@ -57,7 +57,7 @@ class RunMigrationsTest { } val migrate by tasks.registering(MpsMigrate::class) { - projectDirectories.from("$mpsTestPrjLocation") + projectLocations.from("$mpsTestPrjLocation") mpsHome.set(layout.dir(resolveMps.map { it.destinationDir })) } """.trimIndent() From f9989b58410a1535e3bba6f83e02a9ce131550c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Mon, 13 Apr 2026 17:13:34 +0200 Subject: [PATCH 11/44] Add javaLauncher to MpsTask interface Declared as a function (fun getJavaLauncher()) rather than a Kotlin property to avoid a platform declarations clash with JavaExec.getJavaLauncher(). JavaExec-based tasks satisfy the interface automatically; DefaultTask-based tasks (MpsMigrate) override the function explicitly. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt | 10 ++++++---- src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt | 10 ++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt index 30bfb9a..5b46100 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt @@ -70,9 +70,11 @@ abstract class MpsMigrate @Inject constructor( effectiveProjectLocations().flatMap { objectFactory.fileTree().from(it) } } - @get:Nested - @get:Optional - val javaLauncher: Property = objectFactory.property() + private val javaLauncherProperty: Property = objectFactory.property() + + @Nested + @Optional + override fun getJavaLauncher(): Property = javaLauncherProperty @get:Input val jvmArgs: ListProperty = objectFactory.listProperty() @@ -133,7 +135,7 @@ abstract class MpsMigrate @Inject constructor( mainClass.set("org.apache.tools.ant.launch.Launcher") workingDir = temporaryDir classpath = mpsAntClasspath - val executableCandidate = javaLauncher.orNull?.executablePath?.asFile?.toString() + val executableCandidate = getJavaLauncher().orNull?.executablePath?.asFile?.toString() if (executableCandidate != null) { executable = executableCandidate } diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt index f2f366e..4328d54 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt @@ -3,6 +3,8 @@ package de.itemis.mps.gradle.tasks import org.gradle.api.Incubating import org.gradle.api.Task import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.jvm.toolchain.JavaLauncher /** * A Gradle task that operates on an MPS installation. @@ -13,4 +15,12 @@ interface MpsTask : Task { * The MPS installation directory. */ val mpsHome: DirectoryProperty + + /** + * The Java launcher to use for running MPS. Each MPS version requires a specific Java version. + * + * Declared as a function rather than a Kotlin property to avoid a platform declarations clash + * with [org.gradle.api.tasks.JavaExec.getJavaLauncher]. + */ + fun getJavaLauncher(): Property } From b92c41bfee65fccce607ea023f5844c9d6e3485d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Mon, 13 Apr 2026 17:15:38 +0200 Subject: [PATCH 12/44] Implement MpsProjectTask on Remigrate Add projectLocation from interface. Rename projectDirectories to projectLocations (mutually exclusive with projectLocation). Co-Authored-By: Claude Opus 4.6 (1M context) --- .../de/itemis/mps/gradle/tasks/Remigrate.kt | 43 +++++++++++++------ .../kotlin/test/migration/RemigrateTest.kt | 2 +- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt index bb349d9..a654d7f 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt @@ -4,10 +4,12 @@ import de.itemis.mps.gradle.BackendConfigurations import de.itemis.mps.gradle.TaskGroups import de.itemis.mps.gradle.launcher.MpsBackendBuilder import de.itemis.mps.gradle.launcher.MpsVersionDetection +import org.gradle.api.GradleException import org.gradle.api.Incubating import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.Directory import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.FileCollection import org.gradle.api.logging.LogLevel import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.MapProperty @@ -25,34 +27,39 @@ import javax.inject.Inject @Incubating @UntrackedTask(because = "Operates 'in place'") open class Remigrate @Inject constructor( - objectFactory: ObjectFactory, + private val objectFactory: ObjectFactory, providerFactory: ProviderFactory -) : JavaExec() { +) : JavaExec(), MpsProjectTask { @get:Input - val logLevel: Property = objectFactory.property().convention(project.gradle.startParameter.logLevel) + override val logLevel: Property = objectFactory.property().convention(project.gradle.startParameter.logLevel) - @get:Internal - val mpsHome: DirectoryProperty = objectFactory.directoryProperty() + @get:Internal("covered by mpsVersion and classpath") + override val mpsHome: DirectoryProperty = objectFactory.directoryProperty() @get:Input @get:Optional - val mpsVersion: Property = objectFactory.property() + override val mpsVersion: Property = objectFactory.property() .convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) @get:Internal("covered by allProjectFiles") - val projectDirectories: ConfigurableFileCollection = objectFactory.fileCollection() + override val projectLocation: DirectoryProperty = objectFactory.directoryProperty() + + @get:Internal("covered by allProjectFiles") + val projectLocations: ConfigurableFileCollection = objectFactory.fileCollection() @get:InputFiles @get:SkipWhenEmpty @get:IgnoreEmptyDirectories - protected val allProjectFiles = providerFactory.provider { projectDirectories.flatMap { objectFactory.fileTree().from(it) } } + protected val allProjectFiles = providerFactory.provider { + effectiveProjectLocations().flatMap { objectFactory.fileTree().from(it) } + } @get:Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") - val folderMacros: MapProperty = objectFactory.mapProperty() + override val folderMacros: MapProperty = objectFactory.mapProperty() @get:Classpath - val pluginRoots: ConfigurableFileCollection = objectFactory.fileCollection() + override val pluginRoots: ConfigurableFileCollection = objectFactory.fileCollection() @get:Internal val additionalClasspath: ConfigurableFileCollection = @@ -75,7 +82,7 @@ open class Remigrate @Inject constructor( argumentProviders.add(CommandLineArgumentProvider { val result = mutableListOf() - for (dir in projectDirectories) { + for (dir in effectiveProjectLocations()) { result.add("--project=$dir") } @@ -111,12 +118,24 @@ open class Remigrate @Inject constructor( @TaskAction override fun exec() { - for (dir in projectDirectories) { + for (dir in effectiveProjectLocations()) { checkProjectLocation(dir) } super.exec() } + private fun effectiveProjectLocations(): FileCollection { + val hasMultiple = !projectLocations.isEmpty + val hasSingle = projectLocation.isPresent + if (hasMultiple && hasSingle) { + throw GradleException("Cannot set both projectLocation and projectLocations. Use one or the other.") + } + if (!hasMultiple && !hasSingle) { + throw GradleException("Must set either projectLocation or projectLocations.") + } + return if (hasMultiple) projectLocations else objectFactory.fileCollection().from(projectLocation) + } + private fun initialBackendClasspath() = mpsHome.asFileTree.matching { include("lib/**/*.jar") } diff --git a/src/test/kotlin/test/migration/RemigrateTest.kt b/src/test/kotlin/test/migration/RemigrateTest.kt index 2aea8a6..a0d9996 100644 --- a/src/test/kotlin/test/migration/RemigrateTest.kt +++ b/src/test/kotlin/test/migration/RemigrateTest.kt @@ -60,7 +60,7 @@ class RemigrateTest { } val remigrate by tasks.registering(Remigrate::class) { - projectDirectories.from("$mpsTestPrjLocation") + projectLocations.from("$mpsTestPrjLocation") mpsHome.set(layout.dir(resolveMps.map { it.destinationDir })) excludedModuleMigrations.add(ExcludedModuleMigration("foo", 0)) From 576d40a10fbd0fe715570866b7df6f246bb9b721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Mon, 13 Apr 2026 17:17:02 +0200 Subject: [PATCH 13/44] Implement MpsTask on RunAntScript Add mpsHome and javaLauncher. Derive Ant classpath from mpsHome when scriptClasspath is not set. Pass mps.home and mps_home as Ant properties. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../de/itemis/mps/gradle/RunAntScript.kt | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt b/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt index 9feab89..62d8925 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt @@ -1,16 +1,17 @@ package de.itemis.mps.gradle; +import de.itemis.mps.gradle.tasks.MpsTask import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileCollection import org.gradle.api.logging.LogLevel -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFiles -import org.gradle.api.tasks.Optional -import org.gradle.api.tasks.TaskAction +import org.gradle.api.provider.Property +import org.gradle.api.tasks.* +import org.gradle.jvm.toolchain.JavaLauncher import org.gradle.process.ExecOperations import javax.inject.Inject -abstract class RunAntScript : DefaultTask() { +abstract class RunAntScript : DefaultTask(), MpsTask { @Input lateinit var script: Any @Input @@ -28,6 +29,15 @@ abstract class RunAntScript : DefaultTask() { @get:Inject protected abstract val execOperations: ExecOperations + @get:Internal + abstract override val mpsHome: DirectoryProperty + + private val javaLauncherProperty: Property = project.objects.property(JavaLauncher::class.java) + + @Nested + @Optional + override fun getJavaLauncher(): Property = javaLauncherProperty + /** * Whether to build incrementally. * @@ -67,9 +77,30 @@ abstract class RunAntScript : DefaultTask() { allArgs += "-Dmps.generator.skipUnmodifiedModels=true" } + if (mpsHome.isPresent) { + val mpsHomePath = mpsHome.get().asFile.absolutePath + if (!allArgs.any { it.startsWith("-Dmps.home=") }) { + allArgs += "-Dmps.home=$mpsHomePath" + } + if (!allArgs.any { it.startsWith("-Dmps_home=") }) { + allArgs += "-Dmps_home=$mpsHomePath" + } + } + val targets = if (incremental) { targets - "clean" } else { targets } - val effectiveExecutable = executable ?: project.findProperty("itemis.mps.gradle.ant.defaultJavaExecutable") + val effectiveExecutable = executable + ?: getJavaLauncher().orNull?.executablePath?.asFile + ?: project.findProperty("itemis.mps.gradle.ant.defaultJavaExecutable") + + val effectiveClasspath: FileCollection? = scriptClasspath ?: if (mpsHome.isPresent) { + mpsHome.asFileTree.matching { + include("lib/ant/lib/*.jar") + include("lib/*.jar") + } + } else { + null + } execOperations.javaexec { if (effectiveExecutable != null) { @@ -86,8 +117,8 @@ abstract class RunAntScript : DefaultTask() { } } - if (scriptClasspath != null) { - classpath(scriptClasspath) + if (effectiveClasspath != null) { + classpath(effectiveClasspath) } args(allArgs + "-buildfile" + project.file(script).toString() + targets) From 268e6b7c4bd570a9a82a3bc2f8a4a93ce63bd65a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Mon, 13 Apr 2026 17:28:43 +0200 Subject: [PATCH 14/44] Remove addVarMacros and dead addPluginRoots overload Co-Authored-By: Claude Opus 4.6 (1M context) --- .../de/itemis/mps/gradle/tasks/backend_arguments.kt | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt index 47cf84c..e78e182 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt @@ -4,11 +4,10 @@ import de.itemis.mps.gradle.ErrorMessages import org.gradle.api.GradleException import org.gradle.api.file.Directory import org.gradle.api.file.FileCollection -import org.gradle.api.file.FileSystemLocation import org.gradle.api.provider.Provider import java.io.File -internal fun checkProjectLocation(projectLocation: Provider) = +internal fun checkProjectLocation(projectLocation: Provider) = checkProjectLocation(projectLocation.get().asFile) internal fun checkProjectLocation(projectLocation: File) { @@ -21,14 +20,6 @@ internal fun addPluginRoots(result: MutableCollection, pluginRoots: File pluginRoots.mapTo(result) { "--plugin-root=$it" } } -internal fun addPluginRoots(result: MutableCollection, pluginRoots: Iterable) { - pluginRoots.mapTo(result) { "--plugin-root=$it" } -} - internal fun addFolderMacros(result: MutableCollection, folderMacros: Provider>) { folderMacros.get().mapTo(result) { "--macro=${it.key}::${it.value.asFile}" } } - -internal fun addVarMacros(result: MutableCollection, varMacros: Provider>) { - varMacros.get().mapTo(result) { "--macro=${it.key}::${it.value}" } -} From 2a1cb7d35b600286bfb1883d9342770e6432b10a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Mon, 13 Apr 2026 17:31:18 +0200 Subject: [PATCH 15/44] Add integration tests for MpsTask and MpsProjectTask withType configuration Co-Authored-By: Claude Opus 4.6 (1M context) --- src/test/kotlin/test/MpsTaskInterfaceTest.kt | 114 +++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 src/test/kotlin/test/MpsTaskInterfaceTest.kt diff --git a/src/test/kotlin/test/MpsTaskInterfaceTest.kt b/src/test/kotlin/test/MpsTaskInterfaceTest.kt new file mode 100644 index 0000000..475a40f --- /dev/null +++ b/src/test/kotlin/test/MpsTaskInterfaceTest.kt @@ -0,0 +1,114 @@ +package test + +import org.gradle.testkit.runner.GradleRunner +import org.hamcrest.CoreMatchers.containsString +import org.hamcrest.MatcherAssert.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder + +class MpsTaskInterfaceTest { + @Rule + @JvmField + val testProjectDir: TemporaryFolder = TemporaryFolder() + + @Test + fun `withType MpsProjectTask configures all project tasks`() { + testProjectDir.newFile("settings.gradle.kts").writeText( + """ + plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version ("0.7.0") + } + """.trimIndent() + ) + + testProjectDir.newFile("build.gradle.kts").writeText( + """ + import de.itemis.mps.gradle.tasks.* + + plugins { + id("de.itemis.mps.gradle.common") + } + + val generate by tasks.registering(MpsGenerate::class) + val check by tasks.registering(MpsCheck::class) { + junitFile.set(layout.buildDirectory.file("output.xml")) + } + val execute by tasks.registering(MpsExecute::class) { + module.set("test") + className.set("test.Class") + method.set("run") + } + + tasks.withType().configureEach { + mpsHome.set(layout.projectDirectory.dir("test-mps-home")) + projectLocation.set(layout.projectDirectory.dir("test-project")) + } + + tasks.register("printConfig") { + doLast { + tasks.withType(MpsProjectTask::class.java).forEach { + println("TASK:${'$'}{it.name}:mpsHome=${'$'}{it.mpsHome.get()}:project=${'$'}{it.projectLocation.get()}") + } + } + } + """.trimIndent() + ) + + val result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments("printConfig") + .withPluginClasspath() + .build() + + assertThat(result.output, containsString("TASK:generate:mpsHome=")) + assertThat(result.output, containsString("TASK:check:mpsHome=")) + assertThat(result.output, containsString("TASK:execute:mpsHome=")) + assertThat(result.output, containsString("test-mps-home")) + assertThat(result.output, containsString("test-project")) + } + + @Test + fun `withType MpsTask configures RunAntScript tasks`() { + testProjectDir.newFile("settings.gradle.kts") + + testProjectDir.newFile("build.gradle.kts").writeText( + """ + import de.itemis.mps.gradle.BuildLanguages + import de.itemis.mps.gradle.tasks.MpsTask + import de.itemis.mps.gradle.tasks.MpsGenerate + + plugins { + id("de.itemis.mps.gradle.common") + } + + val generate by tasks.registering(MpsGenerate::class) + val buildLangs by tasks.registering(BuildLanguages::class) { + script = "build.xml" + } + + tasks.withType().configureEach { + mpsHome.set(layout.projectDirectory.dir("shared-mps")) + } + + tasks.register("printConfig") { + doLast { + tasks.withType(MpsTask::class.java).forEach { + println("TASK:${'$'}{it.name}:mpsHome=${'$'}{it.mpsHome.get()}") + } + } + } + """.trimIndent() + ) + + val result = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withArguments("printConfig") + .withPluginClasspath() + .build() + + assertThat(result.output, containsString("TASK:generate:mpsHome=")) + assertThat(result.output, containsString("TASK:buildLangs:mpsHome=")) + assertThat(result.output, containsString("shared-mps")) + } +} From f0450f80bcd7a2cfbf21fa3b761864ef020bb6e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Mon, 13 Apr 2026 18:14:15 +0200 Subject: [PATCH 16/44] Regenerate API file for MpsTask/MpsProjectTask interfaces Co-Authored-By: Claude Opus 4.6 (1M context) --- api/mps-gradle-plugin.api | 86 +++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/api/mps-gradle-plugin.api b/api/mps-gradle-plugin.api index 330cdb3..6a9015b 100644 --- a/api/mps-gradle-plugin.api +++ b/api/mps-gradle-plugin.api @@ -106,7 +106,7 @@ public class de/itemis/mps/gradle/Pom : groovy/lang/GroovyObject { public fun withProvidedDep (Lorg/gradle/api/publish/maven/MavenPom;Lorg/gradle/api/artifacts/Configuration;)Ljava/lang/Object; } -public abstract class de/itemis/mps/gradle/RunAntScript : org/gradle/api/DefaultTask { +public abstract class de/itemis/mps/gradle/RunAntScript : org/gradle/api/DefaultTask, de/itemis/mps/gradle/tasks/MpsTask { public field script Ljava/lang/Object; public fun ()V public final fun build ()V @@ -116,6 +116,8 @@ public abstract class de/itemis/mps/gradle/RunAntScript : org/gradle/api/Default public final fun getIncludeDefaultArgs ()Z public final fun getIncludeDefaultClasspath ()Z public final fun getIncremental ()Z + public fun getJavaLauncher ()Lorg/gradle/api/provider/Property; + public abstract fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; public final fun getScript ()Ljava/lang/Object; public final fun getScriptArgs ()Ljava/util/List; public final fun getScriptClasspath ()Lorg/gradle/api/file/FileCollection; @@ -158,46 +160,45 @@ public final class de/itemis/mps/gradle/tasks/ExcludedModuleMigration { public fun toString ()Ljava/lang/String; } -public abstract class de/itemis/mps/gradle/tasks/MpsCheck : org/gradle/api/tasks/JavaExec, org/gradle/api/tasks/VerificationTask { +public abstract class de/itemis/mps/gradle/tasks/MpsCheck : org/gradle/api/tasks/JavaExec, de/itemis/mps/gradle/tasks/MpsProjectTask, org/gradle/api/tasks/VerificationTask { public fun ()V public fun exec ()V public final fun getAdditionalModelcheckBackendClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; protected final fun getCompiledClasses ()Lorg/gradle/api/file/FileTree; public final fun getExcludeModels ()Lorg/gradle/api/provider/ListProperty; public final fun getExcludeModules ()Lorg/gradle/api/provider/ListProperty; - public final fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; + public fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; public final fun getJunitFile ()Lorg/gradle/api/file/RegularFileProperty; public final fun getJunitFormat ()Lorg/gradle/api/provider/Property; - public final fun getLogLevel ()Lorg/gradle/api/provider/Property; + public fun getLogLevel ()Lorg/gradle/api/provider/Property; public final fun getModels ()Lorg/gradle/api/provider/ListProperty; public final fun getModules ()Lorg/gradle/api/provider/ListProperty; - public final fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; - public final fun getMpsVersion ()Lorg/gradle/api/provider/Property; + public fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; + public fun getMpsVersion ()Lorg/gradle/api/provider/Property; public final fun getParallel ()Lorg/gradle/api/provider/Property; - public final fun getPluginRoots ()Lorg/gradle/api/provider/SetProperty; - public final fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; + public fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; + public fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; protected final fun getSources ()Lorg/gradle/api/file/FileTree; - public final fun getVarMacros ()Lorg/gradle/api/provider/MapProperty; public final fun getWarningAsError ()Lorg/gradle/api/provider/Property; } -public abstract class de/itemis/mps/gradle/tasks/MpsExecute : org/gradle/api/tasks/JavaExec { +public abstract class de/itemis/mps/gradle/tasks/MpsExecute : org/gradle/api/tasks/JavaExec, de/itemis/mps/gradle/tasks/MpsProjectTask { public fun ()V public fun exec ()V public final fun getAdditionalExecuteBackendClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; public abstract fun getClassName ()Lorg/gradle/api/provider/Property; + public abstract fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; public abstract fun getLogLevel ()Lorg/gradle/api/provider/Property; - public abstract fun getMacros ()Lorg/gradle/api/provider/MapProperty; public abstract fun getMethod ()Lorg/gradle/api/provider/Property; public abstract fun getMethodArguments ()Lorg/gradle/api/provider/ListProperty; public abstract fun getModule ()Lorg/gradle/api/provider/Property; public abstract fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; public abstract fun getMpsVersion ()Lorg/gradle/api/provider/Property; - public abstract fun getPluginRoots ()Lorg/gradle/api/provider/SetProperty; + public abstract fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; public abstract fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; } -public abstract class de/itemis/mps/gradle/tasks/MpsGenerate : org/gradle/api/tasks/JavaExec { +public abstract class de/itemis/mps/gradle/tasks/MpsGenerate : org/gradle/api/tasks/JavaExec, de/itemis/mps/gradle/tasks/MpsProjectTask { public fun ()V public fun exec ()V public final fun getAdditionalGenerateBackendClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; @@ -205,52 +206,65 @@ public abstract class de/itemis/mps/gradle/tasks/MpsGenerate : org/gradle/api/ta public final fun getEnvironmentKind ()Lorg/gradle/api/provider/Property; public final fun getExcludeModels ()Lorg/gradle/api/provider/ListProperty; public final fun getExcludeModules ()Lorg/gradle/api/provider/ListProperty; - public final fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; - public final fun getLogLevel ()Lorg/gradle/api/provider/Property; + public fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; + public fun getLogLevel ()Lorg/gradle/api/provider/Property; public final fun getModels ()Lorg/gradle/api/provider/ListProperty; public final fun getModules ()Lorg/gradle/api/provider/ListProperty; - public final fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; - public final fun getMpsVersion ()Lorg/gradle/api/provider/Property; + public fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; + public fun getMpsVersion ()Lorg/gradle/api/provider/Property; public final fun getParallelGenerationThreads ()Lorg/gradle/api/provider/Property; - public final fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; - public final fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; + public fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; + public fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; protected final fun getSources ()Lorg/gradle/api/file/FileTree; public final fun getStrictMode ()Lorg/gradle/api/provider/Property; - public final fun getVarMacros ()Lorg/gradle/api/provider/MapProperty; } -public abstract class de/itemis/mps/gradle/tasks/MpsMigrate : org/gradle/api/DefaultTask { +public abstract class de/itemis/mps/gradle/tasks/MpsMigrate : org/gradle/api/DefaultTask, de/itemis/mps/gradle/tasks/MpsProjectTask { public fun (Lorg/gradle/api/model/ObjectFactory;Lorg/gradle/api/provider/ProviderFactory;)V public final fun execute ()V protected final fun getAllProjectFiles ()Lorg/gradle/api/provider/Provider; public final fun getAntJvmArgs ()Lorg/gradle/api/provider/ListProperty; protected abstract fun getExecOperations ()Lorg/gradle/process/ExecOperations; - public final fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; + public fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; public final fun getHaltOnDependencyError ()Lorg/gradle/api/provider/Property; public final fun getHaltOnPrecheckFailure ()Lorg/gradle/api/provider/Property; - public final fun getJavaExecutable ()Lorg/gradle/api/file/RegularFileProperty; - public final fun getJavaLauncher ()Lorg/gradle/api/provider/Property; + public fun getJavaLauncher ()Lorg/gradle/api/provider/Property; public final fun getJvmArgs ()Lorg/gradle/api/provider/ListProperty; - public final fun getLogLevel ()Lorg/gradle/api/provider/Property; + public fun getLogLevel ()Lorg/gradle/api/provider/Property; public final fun getMaxHeapSize ()Lorg/gradle/api/provider/Property; - public final fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; - public final fun getMpsVersion ()Lorg/gradle/api/provider/Property; - public final fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; - public final fun getProjectDirectories ()Lorg/gradle/api/file/ConfigurableFileCollection; + public fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; + public fun getMpsVersion ()Lorg/gradle/api/provider/Property; + public fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; + public fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; + public final fun getProjectLocations ()Lorg/gradle/api/file/ConfigurableFileCollection; +} + +public abstract interface class de/itemis/mps/gradle/tasks/MpsProjectTask : de/itemis/mps/gradle/tasks/MpsTask { + public abstract fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; + public abstract fun getLogLevel ()Lorg/gradle/api/provider/Property; + public abstract fun getMpsVersion ()Lorg/gradle/api/provider/Property; + public abstract fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; + public abstract fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; +} + +public abstract interface class de/itemis/mps/gradle/tasks/MpsTask : org/gradle/api/Task { + public abstract fun getJavaLauncher ()Lorg/gradle/api/provider/Property; + public abstract fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; } -public class de/itemis/mps/gradle/tasks/Remigrate : org/gradle/api/tasks/JavaExec { +public class de/itemis/mps/gradle/tasks/Remigrate : org/gradle/api/tasks/JavaExec, de/itemis/mps/gradle/tasks/MpsProjectTask { public fun (Lorg/gradle/api/model/ObjectFactory;Lorg/gradle/api/provider/ProviderFactory;)V public final fun excludeModuleMigration (Ljava/lang/String;I)V public fun exec ()V public final fun getAdditionalClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; protected final fun getAllProjectFiles ()Lorg/gradle/api/provider/Provider; public final fun getExcludedModuleMigrations ()Lorg/gradle/api/provider/SetProperty; - public final fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; - public final fun getLogLevel ()Lorg/gradle/api/provider/Property; - public final fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; - public final fun getMpsVersion ()Lorg/gradle/api/provider/Property; - public final fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; - public final fun getProjectDirectories ()Lorg/gradle/api/file/ConfigurableFileCollection; + public fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; + public fun getLogLevel ()Lorg/gradle/api/provider/Property; + public fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; + public fun getMpsVersion ()Lorg/gradle/api/provider/Property; + public fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; + public fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; + public final fun getProjectLocations ()Lorg/gradle/api/file/ConfigurableFileCollection; } From 71f675086d796750f63bf4b7ffa0a1368c9231ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Tue, 14 Apr 2026 11:10:44 +0200 Subject: [PATCH 17/44] Add 3.0.0 changelog entries Co-Authored-By: Claude Opus 4.6 (1M context) --- CHANGELOG.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e297ae..e8669f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 3.0.0 (Unreleased) -- TBD +### Removed + +- Old plugins (`generate-models`, `modelcheck`, `run-migrations`, `download-jbr`) have been removed. Use the task types + (`MpsGenerate`, `MpsCheck`, `MpsMigrate`, `Remigrate`, `DownloadJbrForPlatform`) directly instead. + +### Added + +- `MpsTask` interface for any task that operates on an MPS installation. Provides `mpsHome`, `mpsVersion`, and + `javaLauncher` properties. Implemented by all MPS task types including `RunAntScript`. +- `MpsProjectTask` interface (extends `MpsTask`) for tasks that operate on MPS projects. Provides `projectLocation`, + `pluginRoots`, `folderMacros`, and `logLevel` properties. Implemented by `MpsGenerate`, `MpsCheck`, `MpsExecute`, + `MpsMigrate`, and `Remigrate`. +- Both interfaces allow bulk configuration via `tasks.withType()` and `tasks.withType()`. + +### Changed + +- `MpsCheck`, `MpsExecute`: `pluginRoots` changed from `SetProperty` to `ConfigurableFileCollection`. +- `MpsCheck`, `MpsExecute`: `macros`/`varMacros` replaced with `folderMacros: MapProperty`. +- `MpsMigrate`, `Remigrate`: `projectDirectories` renamed to `projectLocations`. +- `MpsMigrate`: `javaExecutable` removed in favor of `javaLauncher` from `MpsTask`. +- `RunAntScript`: derives Ant classpath from `mpsHome` when `scriptClasspath` is not set. Passes `mps.home` and + `mps_home` as Ant properties. ## 1.30.1 From e80418b2f6f3c62a7c376ad27844a176dc36b2da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Tue, 14 Apr 2026 11:23:07 +0200 Subject: [PATCH 18/44] Update docs for 3.0.0 changes Remove old plugin docs (generate, modelcheck, download-jbr). Update task docs to reflect renamed/removed properties and new MpsTask interface on RunAntScript. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/plugins/download-jbr.md | 57 -------------------- docs/plugins/generate.md | 67 ----------------------- docs/plugins/modelcheck.md | 102 ----------------------------------- docs/tasks/MpsCheck.md | 15 ++---- docs/tasks/MpsExecute.md | 3 +- docs/tasks/MpsGenerate.md | 15 ++---- docs/tasks/MpsMigrate.md | 49 +++-------------- docs/tasks/Remigrate.md | 11 ++-- docs/tasks/RunAntScript.md | 8 ++- 9 files changed, 26 insertions(+), 301 deletions(-) delete mode 100644 docs/plugins/download-jbr.md delete mode 100644 docs/plugins/generate.md delete mode 100644 docs/plugins/modelcheck.md diff --git a/docs/plugins/download-jbr.md b/docs/plugins/download-jbr.md deleted file mode 100644 index ea295d7..0000000 --- a/docs/plugins/download-jbr.md +++ /dev/null @@ -1,57 +0,0 @@ -## Download JetBrains Runtime - -When building MPS projects with the JetBrains Runtime, the JDK/JRE used by MPS and other JetBrains IDEs, it's -required to download the correct version of the runtime. Since the runtime is platform-dependent it is required to -download a platform-dependent binary. While it's possible to add the logic to your own build script, we provide -a convenient way of doing this with a Gradle plugin. - -The `download-jbr` plugin will add new dependencies and a task to your build. It will add a dependency to -`com.jetbrains.jdk:jbr` to your build, you need to make sure that it is available in your dependency repositories. The -[itemis Maven repository](https://artifacts.itemis.cloud/repository/maven-mps) provides this dependency, but you can -create your own with the scripts located in [mbeddr/build.publish.jdk](https://github.com/mbeddr/build.publish.jdk). - -For easy consumption and incremental build support the plugin creates a task `downloadJbr` which exposes the location of -the java executable via the `javaExecutable` and `javaLauncher` properties. See -[the tests](../../src/test/kotlin/test/others/JBRDownloadTest.kt) for an example of how to use it. - -### Usage - - -Kotlin: -``` -plugins { - id("download-jbr") -} - -repositories { - mavenCentral() - maven("https://artifacts.itemis.cloud/repository/maven-mps") -} - -downloadJbr { - jbrVersion = "11_0_6-b520.66" -} -``` - -Groovy: -``` -apply plugin: 'download-jbr' -... - -repositories { - maven { url 'https://artifacts.itemis.cloud/repository/maven-mps' } - mavenCentral() -} - -downloadJbr { - jbrVersion = '11_0_6-b520.66' -} -``` - -### Parameters - -* `jbrVersion` - version of the JBR to download. While this supports maven version selectors we highly recommend not - using wildcards like `*` or `+` in there for reproducible builds. -* `distributionType` - optional distribution type for the JBR to use. Will default to `jbr_jcef` if omitted. -* `downloadDir` - optional directory where the downloaded JBR is downloaded and extracted to. The plugin defaults to - `build/jbrDownload`. diff --git a/docs/plugins/generate.md b/docs/plugins/generate.md deleted file mode 100644 index b1e6e36..0000000 --- a/docs/plugins/generate.md +++ /dev/null @@ -1,67 +0,0 @@ -## `generate` - -Generate a specific or all models in a project without the need for an MPS model. - -While technically possible generating languages with this task makes little sense as there is no way of packaging the -generated artifacts into JAR files. We only recommend using this for simple tasks where user defined models should be -generated in the CI build or from the commandline. - -### Usage - -A minimal build script to generate an MPS project with no external plugins would look like this: - -``` -apply plugin: 'generate-models' - -configurations { - mps -} - -ext.mpsVersion = '2018.3.6' - -generate { - projectLocation = new File("./mps-prj") - mpsConfig = configurations.mps -} - -dependencies { - mps "com.jetbrains:mps:$mpsVersion" -} -``` - -Parameters: -* `mpsConfig` - the configuration used to resolve MPS. Custom plugins are supported via the `pluginLocation` parameter. -* `mpsLocation` - optional location where to place the MPS files if `mpsConfig` is specified, or where to take them from - otherwise. -* `mpsVersion` - optionally overrides automated version detection from `mpsConfig`. Required if you use - a [custom distribution](../notes/custom-mps-distribution.md) of MPS. -* `javaExec` - optional `java` executable to use. -* `pluginLocation` - location where to load the plugins from. Structure needs to be a flat folder structure similar to the - `plugins` directory inside of the MPS installation. -* `plugins` - deprecated, use `pluginsProperty`. -* `pluginsProperty` - optional list of plugins to load before generation is attempted. - The notation is `new Plugin("pluginID", "somePath")`. The first parameter is the plugin id. - For the second parameter `"somePath"` there are several options: - * if it's an absolute path, the plugin is loaded from that path - * if it's a folder located under `pluginLocation` the plugin is loaded from that folder - * otherwise it should be a plugin folder located under the default `mps/plugins` -* `models` - optional list of models to generate. If omitted all models in the project will be generated. Only full name - matched are supported and no RegEx or partial name matching. -* `excludeModels` (since 1.14) - optional list of models to exclude from generating. RegEx can be used for matching multiple models. -* `modules` (since 1.14) - optional list of modules to generate. Expects ordinary name (w/o virtual folders). RegEx can be used for matching multiple modules. - If both parameters, `models` and `modules`, are omitted - all models in the project will be generated, except as - excluded by `excludeModels` and `excludeModules`. -* `excludeModules` (since 1.14) - optional list of modules to exclude from generate. RegEx can be used for matching multiple modules. -* `macros` - optional list of path macros. The notation is `new Macro("name", "value")`. -* `projectLocation` - location of the MPS project to generate. -* `parallelGenerationThreads` (since 1.17) - optional number of threads to use for parallel generation. Defaults to `0`, - which means that parallel generation is turned off. -* `debug` - optionally allows to start the JVM that is used to generated with a debugger. Setting it to `true` will cause - the started JVM to suspend until a debugger is attached. Useful for debugging classloading problems or exceptions during - the build. -* `backendConfig` - optional configuration providing the backend. If not given, the `execute-generators` backend from - [mps-build-backends](https://github.com/mbeddr/mps-build-backends) will be used. -* `environmentKind` - optional kind of environment (MPS or IDEA) to execute the generators in. IDEA environment is used - by default for backwards compatibility but MPS environment may be faster. See [MPS vs IDEA environment](../notes/mps-vs-idea-environment.md). -* `maxHeap` (since 1.15) - maximum heap size setting for the JVM that executes the generator. The value is a string - understood by the JVM command line argument `-Xmx` e.g. `3G` or `512M`. diff --git a/docs/plugins/modelcheck.md b/docs/plugins/modelcheck.md deleted file mode 100644 index 3b1024c..0000000 --- a/docs/plugins/modelcheck.md +++ /dev/null @@ -1,102 +0,0 @@ -## `checkModels` - -Run the model check on a subset or all models in a project directly from gradle. - -This functionality currently runs all model checks (typesystem, structure, constrains, etc.) from Gradle. By default, if -any of checks fails, the complete build is failed. All messages (Info, Warning or Error) are reported through log4j to -the command line. - -### Usage - -A minimal build script to check all models in an MPS project with no external plugins would look like this: - -``` -apply plugin: 'modelcheck' - -configurations { - mps -} - -dependencies { - mps "com.jetbrains:mps:$mpsVersion" -} - -ext.mpsVersion = '2018.3.6' - -modelcheck { - projectLocation = new File("./mps-prj") - mpsConfig = configurations.mps - macros = [Macro("mypath", "/your/path")] -} -``` - -Parameters: -* `mpsConfig` - the configuration used to resolve MPS. Custom plugins are supported via the `pluginLocation` parameter. -* `mpsLocation` - optional location where to place the MPS files if `mpsConfig` is specified, or where to take them from - otherwise. -* `mpsVersion` - optionally overrides automated version detection from `mpsConfig`. Required if you use - a [custom distribution](../notes/custom-mps-distribution.md) of MPS. -* `javaExec` - optional `java` executable to use. -* `pluginLocation` - location where to load the plugins from. Structure needs to be a flat folder structure similar to the - `plugins` directory inside of the MPS installation. -* `plugins` - deprecated, use `pluginsProperty`. -* `pluginsProperty` - optional list of plugins to load before generation is attempted. - The notation is `new Plugin("pluginID", "somePath")`. The first parameter is the plugin id. - For the second parameter `"somePath"` there are several options: - * if it's an absolute path, the plugin is loaded from that path - * if it's a folder located under `pluginLocation` the plugin is loaded from that folder - * otherwise it should be a plugin folder located under the default `mps/plugins` -* `models` - optional list of models to check. RegEx can be used for matching multiple models. -* `excludeModels` - optional list of models to exclude from checking. RegEx can be used for matching multiple models. -* `modules` - optional list of modules to check. Expects ordinary name (w/o virtual folders). RegEx can be used for matching multiple modules. - If both parameters, `models` and `modules`, are omitted - all models in the project will be checked, except as - excluded by `excludeModels` and `excludeModules`. -* `excludeModules` - optional list of modules to exclude from checking. RegEx can be used for matching multiple modules. -* `macros` - optional list of path macros. The notation is `new Macro("name", "value")`. -* `projectLocation` - location of the MPS project to check. -* `errorNoFail` - report errors but do not fail the build. -* `warningAsError` - handles warnings as errors and will fail the build if any is found when `errorNoFail` is not set. -* `debug` - optionally allows to start the JVM that is used to load MPS project with a debugger. Setting it to `true` will cause - the started JVM to suspend until a debugger is attached. Useful for debugging classloading problems or exceptions during - the build. -* `junitFile` - allows storing the results of the model check as a JUnit XML file. By default, the file will contain one - testcase for each model that was checked (s. `junitFormat`). -* `junitFormat` - specifies how errors are reported in the JUnit XML file. Possible options: - * `model` (default, deprecated) - generates one test case for each model that was checked. If the model check reported - any error for the model, the test case will contain a failure with the error message. - * `module-and-model` (preferred) - generates one test case for each module and model that was checked. If the model - check reported any error for the model or module, the test case will contain a failure with the error message. - * `message` - generates one testcase for each model check error. For uniqueness reasons, the name of the testcase will - reflect the specific model check error and the name of the test class will be constructed from the checked node ID - and its containing root node. Full error message and the node URL will be reported in the testcase failure. Checked - models will be mapped to test suites with this option. -* `parallel` (since 1.20) - runs model checker in parallel mode. Supported in MPS 2021.3.4. Default is `false`. -* `maxHeap` - maximum heap size setting for the JVM that executes the model checker. This is useful to limit the heap usage - in scenarios like containerized build agents where the OS reported memory limit is not the maximum - to be consumed by the container. The value is a string understood by the JVM command line argument `-Xmx` e.g. `3G` or `512M`. -* `backendConfig` - optional configuration providing the backend. If not given, the `modelcheck` backend from - [mps-build-backends](https://github.com/mbeddr/mps-build-backends) will be used. -* `environmentKind` - optional kind of environment (MPS or IDEA) to execute the generators in. IDEA environment is used - by default for backwards compatibility but MPS environment may be faster. See [MPS vs IDEA environment](../notes/mps-vs-idea-environment.md). - -### Additional Plugins - -By default, only the minimum required set of plugins is loaded. This includes base language and some utilities like the -HTTP server from MPS. If your project requires additional plugins to be loaded this is done by setting plugin location -to the place where your jar files are placed and adding your plugin id and folder name to the `plugins` list: - -``` -apply plugin: 'modelcheck' -... - -modelcheck { - pluginLocation = new File("path/to/my/plugins") - pluginsProperty = [new Plugin("com.mbeddr.core", "mbeddr.core")] - projectLocation = new File("./mps-prj") - mpsConfig = configurations.mps -} - -``` - -Dependencies of the specified plugins are automatically loaded from the `pluginLocation` and the plugins directory of -MPS. If they are not found the build will fail. diff --git a/docs/tasks/MpsCheck.md b/docs/tasks/MpsCheck.md index 26df290..bcce461 100644 --- a/docs/tasks/MpsCheck.md +++ b/docs/tasks/MpsCheck.md @@ -1,13 +1,6 @@ ## `MpsCheck` Task Type -This task improves over the [`modelcheck` plugin](../plugins/modelcheck.md) and fixes some of its deficiencies. - -The `modelcheck` extension provided by the eponymous plugin can only be configured once per Gradle project. Checking -multiple subprojects is not possible without resorting to tricks. In addition, the extension only has limited support -for lazy configuration and does not support Gradle build cache. - -The `MpsCheck` task works similarly to the `checkmodels` task of `modelcheck` plugin but allows defining multiple -instances of itself, supports lazy configuration and caching. +Run the model check on a subset or all models in a project. ### Usage @@ -32,10 +25,8 @@ Parameters: included or excluded from checking. * `additionalModelcheckBackendClasspath` - any extra libraries that should be on the classpath of the modelcheck backend. -* `folderMacros` - path variables/macros that are necessary to open the project. Path macros are not considered part of - Gradle build cache key. -* `varMacros` - non-path variables/macros that are necessary to open the project. Variable macros *are* considered part - of Gradle build cache key. +* `folderMacros` - path variables/macros that are necessary to open the project. Keys are macro names, values are + directories. Path macros are not considered part of Gradle build cache key. * `junitFile` - the JUnit XML file to produce. Defaults to `$buildDir/TEST-${task.name}.xml` * `junitFormat` - specifies how errors are reported in the JUnit XML file. Possible options: * `model` (default, deprecated) - generates one test case for each model that was checked. If the model check reported diff --git a/docs/tasks/MpsExecute.md b/docs/tasks/MpsExecute.md index 528c480..f18e741 100644 --- a/docs/tasks/MpsExecute.md +++ b/docs/tasks/MpsExecute.md @@ -27,7 +27,8 @@ Parameters: * `projectLocation` - the location of the MPS project. Default is the Gradle project directory. * `additionalExecuteBackendClasspath` - any extra libraries that should be on the classpath of the execute backend. -* `macros` - variables/macros that are necessary to open the project. +* `folderMacros` - path variables/macros that are necessary to open the project. Keys are macro names, values are + directories. * `mpsHome` - the home directory of the MPS distribution (or RCP) to use for testing. * `mpsVersion` - the MPS version, such as "2021.3". Default is autodetection by reading `$mpsHome/build.properties`. * `pluginRoots` - directories containing additional plugins to load. diff --git a/docs/tasks/MpsGenerate.md b/docs/tasks/MpsGenerate.md index 2eb75cc..bf91ad2 100644 --- a/docs/tasks/MpsGenerate.md +++ b/docs/tasks/MpsGenerate.md @@ -1,13 +1,6 @@ ## `MpsGenerate` Task Type -This task improves over the [`generate` plugin](../plugins/generate.md) above and fixes some of its deficiencies. - -The `generate` extension provided by the eponymous plugin can only be configured once per Gradle project. Generating -multiple subprojects or multiple sets of models is not possible without resorting to tricks. In addition, the extension -only has limited support for lazy configuration and does not support Gradle build cache. - -The `MpsGenerate` task works similarly to the `generate` task created by the `generate` plugin but allows defining -multiple instances of itself, supports lazy configuration and caching. +Generate a specific or all models in a project. ### Usage @@ -32,10 +25,8 @@ Parameters: included or excluded from generation. * `additionalGenerateBackendClasspath` - any extra libraries that should be on the classpath of the generate backend. -* `folderMacros` - path variables/macros that are necessary to open the project. Path macros are not considered part of - Gradle build cache key. -* `varMacros` - non-path variables/macros that are necessary to open the project. Variable macros *are* considered part - of Gradle build cache key. +* `folderMacros` - path variables/macros that are necessary to open the project. Keys are macro names, values are + directories. Path macros are not considered part of Gradle build cache key. * `mpsHome` - the home directory of the MPS distribution (or RCP) to use for testing. * `mpsVersion` - the MPS version, such as "2021.3". Autodetected by reading `$mpsHome/build.properties` by default. * `pluginRoots` - directories with additional plugins to load. diff --git a/docs/tasks/MpsMigrate.md b/docs/tasks/MpsMigrate.md index ab3d7f2..8b6f0b3 100644 --- a/docs/tasks/MpsMigrate.md +++ b/docs/tasks/MpsMigrate.md @@ -16,7 +16,7 @@ tasks.register('migrate', MpsMigrate) { mpsHome = mpsHomeDir // MpsMigrate task can migrate multiple projects at once - projectDirectories.from(projectDir) + projectLocations.from(projectDir) ... } @@ -28,47 +28,10 @@ Parameters: * `mpsVersion` - the MPS version, such as "2021.3". Autodetected by reading `$mpsHome/build.properties` by default. * `haltOnPrecheckFailure` - fail if the migration pre-check (e.g. broken references) fails. * `haltOnDependencyError` - fail if non-migrated dependencies are found. -* `projectDirectories` - project directories to migrate. -* `folderMacros` - path variables/macros that are necessary to open the project. Path macros are not considered part of - Gradle build cache key. +* `projectLocation` or `projectLocations` - the project or projects to migrate. The properties are mutually exclusive, + exactly one should be set. +* `folderMacros` - path variables/macros that are necessary to open the project. Keys are macro names, values are + directories. Path macros are not considered part of Gradle build cache key. * `pluginRoots` - directories that will be searched (recursively) for additional plugins to load. - -## Run migrations - -Run all pending migrations in the project. - -### Usage - -A minimal build script to check all models in an MPS project with no external plugins would look like this: - -``` -apply plugin: 'run-migrations"' - -configurations { - mps -} - -dependencies { - mps "com.jetbrains:mps:$mpsVersion" -} - -runMigrations { - projectLocation = new File("./mps-prj") - mpsConfig = configurations.mps -} -``` - -Parameters: -* `mpsConfig` - the configuration used to resolve MPS. -* `mpsLocation` - optional location where to place the MPS files if `mpsConfig` is specified, or where to take them from - otherwise. -* `mpsVersion` - optionally overrides automated version detection from `mpsConfig`. Required if you use - a [custom distribution](../notes/custom-mps-distribution.md) of MPS. -* `projectLocation` - location of the project that should be migrated. -* `force` - ignores the marker files for projects which allow pending migrations, migrate them anyway. Supported in 2021.3.0 and higher. -* `haltOnPrecheckFailure` - controls whether migration is aborted if pre-checks fail (except the check for migrated dependencies) Default: `true`. Supported in 2021.1 and higher. -* `haltOnDependencyError` - controls whether migration is aborted when non-migrated dependencies are discovered. Default: `true`. Supported in 2021.3.4 and 2023.2 and higher. -* `maxHeap` (since 1.15) - maximum heap size setting for the JVM that executes the migrations. The value is a string +* `maxHeapSize` - maximum heap size setting for the JVM that executes the migrations. The value is a string understood by the JVM command line argument `-Xmx` e.g. `3G` or `512M`. - -At least `mpsConfig` or `mpsLocation` + `mpsVersion` must be set. diff --git a/docs/tasks/Remigrate.md b/docs/tasks/Remigrate.md index 13d9ab3..f74ead1 100644 --- a/docs/tasks/Remigrate.md +++ b/docs/tasks/Remigrate.md @@ -16,8 +16,8 @@ tasks.register('remigrate', Remigrate) { mpsHome = mpsHomeDir // Remigrate task can run migrations on multiple projects - projectDirectories.from(projectDir1) - projectDirectories.from(projectDir2) + projectLocations.from(projectDir1) + projectLocations.from(projectDir2) } ``` @@ -25,9 +25,10 @@ Parameters: * `mpsHome` - the home directory of the MPS distribution (or RCP) to use for testing. * `mpsVersion` - the MPS version, such as "2021.3". Autodetected by reading `$mpsHome/build.properties` by default. -* `projectDirectories` - project directories to migrate. -* `folderMacros` - path variables/macros that are necessary to open the project. Path macros are not considered part of - Gradle build cache key. +* `projectLocation` or `projectLocations` - the project or projects to migrate. The properties are mutually exclusive, + exactly one should be set. +* `folderMacros` - path variables/macros that are necessary to open the project. Keys are macro names, values are + directories. Path macros are not considered part of Gradle build cache key. * `pluginRoots` - directories that will be searched (recursively) for additional plugins to load. ### Operation diff --git a/docs/tasks/RunAntScript.md b/docs/tasks/RunAntScript.md index dbfd1c7..8b37bf6 100644 --- a/docs/tasks/RunAntScript.md +++ b/docs/tasks/RunAntScript.md @@ -10,11 +10,15 @@ because they may not exist yet when the build is started. Parameters: -- `script`: path to the ANT to execute +- `script`: path to the ANT to execute. - `scriptClasspath`: classpath used for the JVM that will execute the generated ANT script. Needs to contain ANT to be - able to run the build script. See below section "Providing Global Defaults" for project wide defaults. + able to run the build script. If not set and `mpsHome` is set, the classpath is derived from the MPS installation. + See below section "Providing Global Defaults" for project wide defaults. - `scriptArgs`: additional command line arguments provided to the JVM that will execute the generated ANT scripts. This is often used to provide property valued via `-Dprop=value`. See below section "Providing Global Defaults" for project wide defaults. +- `mpsHome`: the MPS installation directory. When set, `mps.home` and `mps_home` are passed as Ant properties + automatically, and the Ant classpath is derived from the MPS installation if `scriptClasspath` is not set. +- `javaLauncher`: the Java launcher to use for running MPS. Takes precedence over `executable` and the global default. - `executable`: the `java` executable to use. Optional. If `itemis.mps.gradle.ant.defaultJavaExecutable` extended property is set, its value is used as the default value for the parameter. - `includeDefaultArgs`: controls whether the project-wide default values for arguments are used. From c3561af33532f1c2fc53e2163ab6a20ce589037e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Tue, 14 Apr 2026 11:28:00 +0200 Subject: [PATCH 19/44] Use Kotlin property assignment syntax for Gradle properties Replace prop.set(value) with prop = value in build scripts and test build script strings where the Gradle Kotlin DSL supports it. Co-Authored-By: Claude Opus 4.6 (1M context) --- build.gradle.kts | 12 +++++----- src/test/kotlin/test/MpsTaskInterfaceTest.kt | 14 +++++------ .../test/codeexecution/MpsExecuteTaskTest.kt | 24 +++++++++---------- .../kotlin/test/migration/RemigrateTest.kt | 2 +- .../test/migration/RunMigrationsTest.kt | 2 +- .../test/modelchecking/MpsCheckTaskTest.kt | 14 +++++------ .../modelgeneration/MpsGenerateTaskTest.kt | 6 ++--- 7 files changed, 37 insertions(+), 37 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index fe56dda..6405cba 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -96,17 +96,17 @@ publishing { } } pom { - url.set("https://github.com/mbeddr/mps-gradle-plugin") + url = "https://github.com/mbeddr/mps-gradle-plugin" licenses { license { - name.set("The Apache License, Version 2.0") - url.set("https://www.apache.org/licenses/LICENSE-2.0.txt") + name = "The Apache License, Version 2.0" + url = "https://www.apache.org/licenses/LICENSE-2.0.txt" } } scm { - connection.set("scm:git:git://github.com/mbeddr/mps-gradle-plugin.git") - developerConnection.set("scm:git:ssh://github.com/mbeddr/mps-gradle-plugin.git") - url.set("https://github.com/mbeddr/mps-gradle-plugin") + connection = "scm:git:git://github.com/mbeddr/mps-gradle-plugin.git" + developerConnection = "scm:git:ssh://github.com/mbeddr/mps-gradle-plugin.git" + url = "https://github.com/mbeddr/mps-gradle-plugin" } } } diff --git a/src/test/kotlin/test/MpsTaskInterfaceTest.kt b/src/test/kotlin/test/MpsTaskInterfaceTest.kt index 475a40f..b56afdb 100644 --- a/src/test/kotlin/test/MpsTaskInterfaceTest.kt +++ b/src/test/kotlin/test/MpsTaskInterfaceTest.kt @@ -32,17 +32,17 @@ class MpsTaskInterfaceTest { val generate by tasks.registering(MpsGenerate::class) val check by tasks.registering(MpsCheck::class) { - junitFile.set(layout.buildDirectory.file("output.xml")) + junitFile = layout.buildDirectory.file("output.xml") } val execute by tasks.registering(MpsExecute::class) { - module.set("test") - className.set("test.Class") - method.set("run") + module = "test" + className = "test.Class" + method = "run" } tasks.withType().configureEach { - mpsHome.set(layout.projectDirectory.dir("test-mps-home")) - projectLocation.set(layout.projectDirectory.dir("test-project")) + mpsHome = layout.projectDirectory.dir("test-mps-home") + projectLocation = layout.projectDirectory.dir("test-project") } tasks.register("printConfig") { @@ -88,7 +88,7 @@ class MpsTaskInterfaceTest { } tasks.withType().configureEach { - mpsHome.set(layout.projectDirectory.dir("shared-mps")) + mpsHome = layout.projectDirectory.dir("shared-mps") } tasks.register("printConfig") { diff --git a/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt b/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt index af0e136..236a0e5 100644 --- a/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt +++ b/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt @@ -62,18 +62,18 @@ class MpsExecuteTaskTest { val resolvedMpsHome = resolveMps.map { it.destinationDir } val generate by tasks.registering(MpsGenerate::class) { - mpsHome.set(layout.dir(resolvedMpsHome)) - projectLocation.set(file("${mpsTestProjectPath.canonicalPath}")) + mpsHome = layout.dir(resolvedMpsHome) + projectLocation = file("${mpsTestProjectPath.canonicalPath}") doFirst { println(resolvedMpsHome.get().listFiles()?.toList()) } } - + val execute by tasks.registering(MpsExecute::class) { dependsOn(generate) - mpsHome.set(layout.dir(resolvedMpsHome)) - projectLocation.set(file("${mpsTestProjectPath.canonicalPath}")) + mpsHome = layout.dir(resolvedMpsHome) + projectLocation = file("${mpsTestProjectPath.canonicalPath}") doFirst { println(resolvedMpsHome.get()) @@ -85,9 +85,9 @@ class MpsExecuteTaskTest { fun `execute with Project`() { buildFile.writeText(buildScriptBoilerplate("2021.3.4") + """ execute { - module.set("NewSolution") - className.set("NewSolution.myModel.MyClass") - method.set("onlyProject") + module = "NewSolution" + className = "NewSolution.myModel.MyClass" + method = "onlyProject" } """.trimIndent()) @@ -100,11 +100,11 @@ class MpsExecuteTaskTest { fun `execute with Project and args`() { buildFile.writeText(buildScriptBoilerplate("2021.3.4") + """ execute { - module.set("NewSolution") - className.set("NewSolution.myModel.MyClass") - method.set("projectAndArgs") + module = "NewSolution" + className = "NewSolution.myModel.MyClass" + method = "projectAndArgs" - methodArguments.set(listOf("arg1", "arg2")) + methodArguments = listOf("arg1", "arg2") } """.trimIndent()) diff --git a/src/test/kotlin/test/migration/RemigrateTest.kt b/src/test/kotlin/test/migration/RemigrateTest.kt index a0d9996..a80332a 100644 --- a/src/test/kotlin/test/migration/RemigrateTest.kt +++ b/src/test/kotlin/test/migration/RemigrateTest.kt @@ -61,7 +61,7 @@ class RemigrateTest { val remigrate by tasks.registering(Remigrate::class) { projectLocations.from("$mpsTestPrjLocation") - mpsHome.set(layout.dir(resolveMps.map { it.destinationDir })) + mpsHome = layout.dir(resolveMps.map { it.destinationDir }) excludedModuleMigrations.add(ExcludedModuleMigration("foo", 0)) excludeModuleMigration("bar", 1) diff --git a/src/test/kotlin/test/migration/RunMigrationsTest.kt b/src/test/kotlin/test/migration/RunMigrationsTest.kt index 777dc7e..c5d39fe 100644 --- a/src/test/kotlin/test/migration/RunMigrationsTest.kt +++ b/src/test/kotlin/test/migration/RunMigrationsTest.kt @@ -58,7 +58,7 @@ class RunMigrationsTest { val migrate by tasks.registering(MpsMigrate::class) { projectLocations.from("$mpsTestPrjLocation") - mpsHome.set(layout.dir(resolveMps.map { it.destinationDir })) + mpsHome = layout.dir(resolveMps.map { it.destinationDir }) } """.trimIndent() ) diff --git a/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt b/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt index 75dba67..84e5290 100644 --- a/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt +++ b/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt @@ -57,8 +57,8 @@ class MpsCheckTaskTest { settingsFile.writeText(settingsScriptBoilerplate()) buildFile.writeText(buildScriptBoilerplate("2021.3.3") + """ val checkProject by tasks.registering(MpsCheck::class) { - mpsHome.set(layout.dir(resolveMps.map { it.destinationDir })) - junitFile.set(layout.buildDirectory.file("output.xml")) + mpsHome = layout.dir(resolveMps.map { it.destinationDir }) + junitFile = layout.buildDirectory.file("output.xml") } """.trimIndent()) @@ -79,9 +79,9 @@ class MpsCheckTaskTest { settingsFile.writeText(settingsScriptBoilerplate()) buildFile.writeText(buildScriptBoilerplate("2021.3.3") + """ val checkProject by tasks.registering(MpsCheck::class) { - mpsHome.set(layout.dir(resolveMps.map { it.destinationDir })) - projectLocation.set(file("mps-prj")) - junitFile.set(layout.buildDirectory.file("output.xml")) + mpsHome = layout.dir(resolveMps.map { it.destinationDir }) + projectLocation = file("mps-prj") + junitFile = layout.buildDirectory.file("output.xml") pluginRoots.from(resolveMps.map { File(it.destinationDir, "plugins/mps-console") }) } """.trimIndent()) @@ -104,8 +104,8 @@ class MpsCheckTaskTest { settingsFile.writeText(settingsScriptBoilerplate()) buildFile.writeText(buildScriptBoilerplate("2021.3.3") + """ val checkProject by tasks.registering(MpsCheck::class) { - mpsHome.set(layout.dir(resolveMps.map { it.destinationDir })) - projectLocation.set(file("mps-prj")) + mpsHome = layout.dir(resolveMps.map { it.destinationDir }) + projectLocation = file("mps-prj") } """.trimIndent()) diff --git a/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt b/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt index df46136..801ef17 100644 --- a/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt +++ b/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt @@ -57,7 +57,7 @@ class MpsGenerateTaskTest { settingsFile.writeText(settingsScriptBoilerplate()) buildFile.writeText(buildScriptBoilerplate("2021.3.3") + """ val generateProject by tasks.registering(MpsGenerate::class) { - mpsHome.set(layout.dir(resolveMps.map { it.destinationDir })) + mpsHome = layout.dir(resolveMps.map { it.destinationDir }) } """.trimIndent()) @@ -78,8 +78,8 @@ class MpsGenerateTaskTest { settingsFile.writeText(settingsScriptBoilerplate()) buildFile.writeText(buildScriptBoilerplate("2021.3.3") + """ val generateProject by tasks.registering(MpsGenerate::class) { - mpsHome.set(layout.dir(resolveMps.map { it.destinationDir })) - projectLocation.set(file("mps-prj")) + mpsHome = layout.dir(resolveMps.map { it.destinationDir }) + projectLocation = file("mps-prj") } """.trimIndent()) From cea5bdec8394a0ae3eaec47fc4fd33ff327de237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Tue, 14 Apr 2026 11:29:24 +0200 Subject: [PATCH 20/44] Move mpsVersion to MpsTask and add task annotations to interfaces Move mpsVersion from MpsProjectTask up to MpsTask so it is available on all MPS tasks. Add Gradle task annotations (@Internal, @Input, @Classpath, @Console, @Nested) to interface properties and update doc comment examples to use property assignment syntax. Co-Authored-By: Claude Opus 4.6 (1M context) --- api/mps-gradle-plugin.api | 2 +- .../itemis/mps/gradle/tasks/MpsProjectTask.kt | 18 ++++++++++-------- .../de/itemis/mps/gradle/tasks/MpsTask.kt | 13 +++++++++++++ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/api/mps-gradle-plugin.api b/api/mps-gradle-plugin.api index 6a9015b..e26ff80 100644 --- a/api/mps-gradle-plugin.api +++ b/api/mps-gradle-plugin.api @@ -242,7 +242,6 @@ public abstract class de/itemis/mps/gradle/tasks/MpsMigrate : org/gradle/api/Def public abstract interface class de/itemis/mps/gradle/tasks/MpsProjectTask : de/itemis/mps/gradle/tasks/MpsTask { public abstract fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; public abstract fun getLogLevel ()Lorg/gradle/api/provider/Property; - public abstract fun getMpsVersion ()Lorg/gradle/api/provider/Property; public abstract fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; public abstract fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; } @@ -250,6 +249,7 @@ public abstract interface class de/itemis/mps/gradle/tasks/MpsProjectTask : de/i public abstract interface class de/itemis/mps/gradle/tasks/MpsTask : org/gradle/api/Task { public abstract fun getJavaLauncher ()Lorg/gradle/api/provider/Property; public abstract fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; + public abstract fun getMpsVersion ()Lorg/gradle/api/provider/Property; } public class de/itemis/mps/gradle/tasks/Remigrate : org/gradle/api/tasks/JavaExec, de/itemis/mps/gradle/tasks/MpsProjectTask { diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt index 868b542..77d951e 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt @@ -7,6 +7,9 @@ import org.gradle.api.file.DirectoryProperty import org.gradle.api.logging.LogLevel import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property +import org.gradle.api.tasks.Classpath +import org.gradle.api.tasks.Console +import org.gradle.api.tasks.Internal /** * A Gradle task that operates on one or more MPS projects. @@ -15,38 +18,37 @@ import org.gradle.api.provider.Property * * ```kotlin * tasks.withType().configureEach { - * mpsHome.set(layout.projectDirectory.dir("mps")) - * projectLocation.set(layout.projectDirectory.dir("my-mps-project")) - * pluginRoots.from(layout.projectDirectory.dir("plugins")) + * mpsHome = layout.projectDirectory.dir("mps") + * projectLocation = layout.projectDirectory.dir("my-mps-project") + * pluginRoots.from(mpsHome.dir("plugins")) * } * ``` */ @Incubating interface MpsProjectTask : MpsTask { - /** - * The MPS version string (e.g. "2021.3.3"). Detected automatically from [mpsHome] if not set explicitly. - */ - val mpsVersion: Property - /** * The MPS project directory. Convention: the Gradle project directory (but no convention is set on * multi-project tasks like MpsMigrate and Remigrate, so that the mutual exclusivity check with * [projectLocations][MpsMigrate.projectLocations] works correctly). */ + @get:Internal("too coarse to be used as input") val projectLocation: DirectoryProperty /** * Root directories containing MPS plugins to load. */ + @get:Classpath val pluginRoots: ConfigurableFileCollection /** * Folder macros (path variables) to pass to MPS. Keys are macro names, values are directories. */ + @get:Internal("not considered input") val folderMacros: MapProperty /** * Log level for the MPS backend process. */ + @get:Console val logLevel: Property } diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt index 4328d54..633c8b8 100644 --- a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt +++ b/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt @@ -4,7 +4,12 @@ import org.gradle.api.Incubating import org.gradle.api.Task import org.gradle.api.file.DirectoryProperty import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Nested +import org.gradle.api.tasks.UntrackedTask import org.gradle.jvm.toolchain.JavaLauncher +import org.gradle.work.DisableCachingByDefault /** * A Gradle task that operates on an MPS installation. @@ -14,13 +19,21 @@ interface MpsTask : Task { /** * The MPS installation directory. */ + @get:Internal("not considered an input by itself") val mpsHome: DirectoryProperty + /** + * The MPS version string (e.g. "2021.3.3"). Detected automatically from [mpsHome] if not set explicitly. + */ + @get:Input + val mpsVersion: Property + /** * The Java launcher to use for running MPS. Each MPS version requires a specific Java version. * * Declared as a function rather than a Kotlin property to avoid a platform declarations clash * with [org.gradle.api.tasks.JavaExec.getJavaLauncher]. */ + @Nested fun getJavaLauncher(): Property } From b39c1200d4d75f5c93c44c33e6323c7e0d833ad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 19:12:18 +0200 Subject: [PATCH 21/44] build: remove .java-version We don't need it --- .java-version | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .java-version diff --git a/.java-version b/.java-version deleted file mode 100644 index 2dbc24b..0000000 --- a/.java-version +++ /dev/null @@ -1 +0,0 @@ -11.0 From 4e059ab4a87e05f2e49a27675c229096c6bbc303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 15:44:53 +0200 Subject: [PATCH 22/44] Move plugin into :mps-gradle-plugin subproject Root becomes a thin aggregator. The plugin's sources, api file, docs, CHANGELOG, README, and build.gradle.kts move under mps-gradle-plugin/. Root build.gradle.kts is gone; setTeamCityBuildNumber and dependency locking live on the subproject now. Maven coordinates (de.itemis.mps:mps-gradle-plugin) are unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) --- buildscript-gradle.lockfile | 35 ------------------- .../CHANGELOG.md | 0 README.md => mps-gradle-plugin/README.md | 0 .../api}/mps-gradle-plugin.api | 0 .../build.gradle.kts | 10 ------ .../docs}/notes/custom-mps-distribution.md | 0 .../docs}/notes/mps-vs-idea-environment.md | 0 .../docs}/tasks/BundleMacosJdk.md | 0 .../docs}/tasks/CreateDmg.md | 0 .../docs}/tasks/GenerateLibrariesXml.md | 0 .../docs}/tasks/MpsCheck.md | 0 .../docs}/tasks/MpsExecute.md | 0 .../docs}/tasks/MpsGenerate.md | 0 .../docs}/tasks/MpsMigrate.md | 0 .../docs}/tasks/Remigrate.md | 0 .../docs}/tasks/RunAntScript.md | 0 .../gradle.lockfile | 2 +- mps-gradle-plugin/settings.gradle.kts | 15 ++++++++ .../itemis/mps/gradle/BundleMacosJdk.groovy | 0 .../itemis/mps/gradle/BundledScripts.groovy | 0 .../de/itemis/mps/gradle/CreateDmg.groovy | 0 .../mps/gradle/GenerateLibrariesXml.groovy | 0 .../itemis/mps/gradle/GetMpsInBrowser.groovy | 0 .../groovy/de/itemis/mps/gradle/Pom.groovy | 0 .../mps/gradle/BackendConfigurations.kt | 0 .../kotlin/de/itemis/mps/gradle/Common.kt | 0 .../de/itemis/mps/gradle/ErrorMessages.kt | 0 .../de/itemis/mps/gradle/RunAntScript.kt | 0 .../kotlin/de/itemis/mps/gradle/TaskGroups.kt | 0 .../de/itemis/mps/gradle/common.gradle.kts | 0 .../de/itemis/mps/gradle/downloadJBR/Tasks.kt | 0 .../downloadJBR/ToolchainSpecFactory.kt | 0 .../gradle/tasks/ExcludedModuleMigration.kt | 0 .../de/itemis/mps/gradle/tasks/Libraries.kt | 0 .../de/itemis/mps/gradle/tasks/MpsCheck.kt | 0 .../de/itemis/mps/gradle/tasks/MpsExecute.kt | 0 .../de/itemis/mps/gradle/tasks/MpsGenerate.kt | 0 .../de/itemis/mps/gradle/tasks/MpsMigrate.kt | 0 .../itemis/mps/gradle/tasks/MpsProjectTask.kt | 0 .../de/itemis/mps/gradle/tasks/MpsTask.kt | 0 .../de/itemis/mps/gradle/tasks/PluginIds.kt | 0 .../de/itemis/mps/gradle/tasks/Remigrate.kt | 0 .../mps/gradle/tasks/backend_arguments.kt | 0 .../itemis/mps/gradle/Mac/Finder/DSStore.pm | 0 .../Mac/Finder/DSStore/BuddyAllocator.pm | 0 .../de/itemis/mps/gradle/bundle_macos_jdk.sh | 0 .../resources/de/itemis/mps/gradle/mpsdmg.pl | 0 .../resources/de/itemis/mps/gradle/mpsdmg.sh | 0 .../resources/de/itemis/mps/gradle/mpssign.sh | 0 .../src}/test/kotlin/support/ProjectHelper.kt | 0 .../test/kotlin/test/MpsTaskInterfaceTest.kt | 0 .../test/codeexecution/MpsExecuteTaskTest.kt | 0 .../kotlin/test/migration/RemigrateTest.kt | 0 .../test/migration/RunMigrationsTest.kt | 0 .../test/modelchecking/MpsCheckTaskTest.kt | 0 .../modelgeneration/MpsGenerateTaskTest.kt | 0 .../others/GenerateProjectLibrariesXmlTest.kt | 0 .../test/kotlin/test/others/PluginIdsTest.kt | 0 .../test-project-with-errors/.mps/.name | 0 .../.mps/encodings.xml | 0 .../.mps/migration.xml | 0 .../test-project-with-errors/.mps/misc.xml | 0 .../test-project-with-errors/.mps/modules.xml | 0 .../test-project-with-errors/.mps/vcs.xml | 0 .../my.solution.with.errors/models/java.mps | 0 .../my.solution.with.errors.msd | 0 .../solutions/my.solution/models/java.mps | 0 .../solutions/my.solution/my.solution.msd | 0 .../resources/test-project/.mps/.gitignore | 0 .../resources/test-project/.mps/migration.xml | 0 .../test/resources/test-project/.mps/misc.xml | 0 .../resources/test-project/.mps/modules.xml | 0 .../test/resources/test-project/.mps/vcs.xml | 0 .../solutions/NewSolution/NewSolution.msd | 0 .../models/NewSolution.myModel.mps | 0 settings.gradle.kts | 2 ++ 76 files changed, 18 insertions(+), 46 deletions(-) delete mode 100644 buildscript-gradle.lockfile rename CHANGELOG.md => mps-gradle-plugin/CHANGELOG.md (100%) rename README.md => mps-gradle-plugin/README.md (100%) rename {api => mps-gradle-plugin/api}/mps-gradle-plugin.api (100%) rename build.gradle.kts => mps-gradle-plugin/build.gradle.kts (94%) rename {docs => mps-gradle-plugin/docs}/notes/custom-mps-distribution.md (100%) rename {docs => mps-gradle-plugin/docs}/notes/mps-vs-idea-environment.md (100%) rename {docs => mps-gradle-plugin/docs}/tasks/BundleMacosJdk.md (100%) rename {docs => mps-gradle-plugin/docs}/tasks/CreateDmg.md (100%) rename {docs => mps-gradle-plugin/docs}/tasks/GenerateLibrariesXml.md (100%) rename {docs => mps-gradle-plugin/docs}/tasks/MpsCheck.md (100%) rename {docs => mps-gradle-plugin/docs}/tasks/MpsExecute.md (100%) rename {docs => mps-gradle-plugin/docs}/tasks/MpsGenerate.md (100%) rename {docs => mps-gradle-plugin/docs}/tasks/MpsMigrate.md (100%) rename {docs => mps-gradle-plugin/docs}/tasks/Remigrate.md (100%) rename {docs => mps-gradle-plugin/docs}/tasks/RunAntScript.md (100%) rename gradle.lockfile => mps-gradle-plugin/gradle.lockfile (98%) create mode 100644 mps-gradle-plugin/settings.gradle.kts rename {src => mps-gradle-plugin/src}/main/groovy/de/itemis/mps/gradle/BundleMacosJdk.groovy (100%) rename {src => mps-gradle-plugin/src}/main/groovy/de/itemis/mps/gradle/BundledScripts.groovy (100%) rename {src => mps-gradle-plugin/src}/main/groovy/de/itemis/mps/gradle/CreateDmg.groovy (100%) rename {src => mps-gradle-plugin/src}/main/groovy/de/itemis/mps/gradle/GenerateLibrariesXml.groovy (100%) rename {src => mps-gradle-plugin/src}/main/groovy/de/itemis/mps/gradle/GetMpsInBrowser.groovy (100%) rename {src => mps-gradle-plugin/src}/main/groovy/de/itemis/mps/gradle/Pom.groovy (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/BackendConfigurations.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/Common.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/ErrorMessages.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/TaskGroups.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/common.gradle.kts (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/downloadJBR/Tasks.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/downloadJBR/ToolchainSpecFactory.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/tasks/ExcludedModuleMigration.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/tasks/Libraries.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/tasks/PluginIds.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt (100%) rename {src => mps-gradle-plugin/src}/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt (100%) rename {src => mps-gradle-plugin/src}/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore.pm (100%) rename {src => mps-gradle-plugin/src}/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore/BuddyAllocator.pm (100%) rename {src => mps-gradle-plugin/src}/main/resources/de/itemis/mps/gradle/bundle_macos_jdk.sh (100%) rename {src => mps-gradle-plugin/src}/main/resources/de/itemis/mps/gradle/mpsdmg.pl (100%) rename {src => mps-gradle-plugin/src}/main/resources/de/itemis/mps/gradle/mpsdmg.sh (100%) rename {src => mps-gradle-plugin/src}/main/resources/de/itemis/mps/gradle/mpssign.sh (100%) rename {src => mps-gradle-plugin/src}/test/kotlin/support/ProjectHelper.kt (100%) rename {src => mps-gradle-plugin/src}/test/kotlin/test/MpsTaskInterfaceTest.kt (100%) rename {src => mps-gradle-plugin/src}/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt (100%) rename {src => mps-gradle-plugin/src}/test/kotlin/test/migration/RemigrateTest.kt (100%) rename {src => mps-gradle-plugin/src}/test/kotlin/test/migration/RunMigrationsTest.kt (100%) rename {src => mps-gradle-plugin/src}/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt (100%) rename {src => mps-gradle-plugin/src}/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt (100%) rename {src => mps-gradle-plugin/src}/test/kotlin/test/others/GenerateProjectLibrariesXmlTest.kt (100%) rename {src => mps-gradle-plugin/src}/test/kotlin/test/others/PluginIdsTest.kt (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project-with-errors/.mps/.name (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project-with-errors/.mps/encodings.xml (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project-with-errors/.mps/migration.xml (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project-with-errors/.mps/misc.xml (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project-with-errors/.mps/modules.xml (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project-with-errors/.mps/vcs.xml (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project-with-errors/solutions/my.solution.with.errors/models/java.mps (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project-with-errors/solutions/my.solution.with.errors/my.solution.with.errors.msd (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project-with-errors/solutions/my.solution/models/java.mps (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project-with-errors/solutions/my.solution/my.solution.msd (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project/.mps/.gitignore (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project/.mps/migration.xml (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project/.mps/misc.xml (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project/.mps/modules.xml (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project/.mps/vcs.xml (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project/solutions/NewSolution/NewSolution.msd (100%) rename {src => mps-gradle-plugin/src}/test/resources/test-project/solutions/NewSolution/models/NewSolution.myModel.mps (100%) diff --git a/buildscript-gradle.lockfile b/buildscript-gradle.lockfile deleted file mode 100644 index 13545f8..0000000 --- a/buildscript-gradle.lockfile +++ /dev/null @@ -1,35 +0,0 @@ -# This is a Gradle generated file for dependency locking. -# Manual edits can break the build and are not advised. -# This file is expected to be part of source control. -com.google.code.gson:gson:2.8.9=classpath -io.github.java-diff-utils:java-diff-utils:4.12=classpath -org.gradle.kotlin.kotlin-dsl:org.gradle.kotlin.kotlin-dsl.gradle.plugin:5.2.0=classpath -org.gradle.kotlin:gradle-kotlin-dsl-plugins:5.2.0=classpath -org.jetbrains.intellij.deps:trove4j:1.0.20200330=classpath -org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:1.7.10=classpath -org.jetbrains.kotlin:kotlin-assignment:2.0.21=classpath -org.jetbrains.kotlin:kotlin-build-statistics:2.0.21=classpath -org.jetbrains.kotlin:kotlin-build-tools-api:2.0.21=classpath -org.jetbrains.kotlin:kotlin-compiler-embeddable:2.0.21=classpath -org.jetbrains.kotlin:kotlin-compiler-runner:2.0.21=classpath -org.jetbrains.kotlin:kotlin-daemon-client:2.0.21=classpath -org.jetbrains.kotlin:kotlin-daemon-embeddable:2.0.21=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-annotations:2.0.21=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-api:2.0.21=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-idea-proto:2.0.21=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-idea:2.0.21=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-model:2.0.21=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21=classpath -org.jetbrains.kotlin:kotlin-gradle-plugins-bom:2.0.21=classpath -org.jetbrains.kotlin:kotlin-klib-commonizer-api:2.0.21=classpath -org.jetbrains.kotlin:kotlin-native-utils:2.0.21=classpath -org.jetbrains.kotlin:kotlin-sam-with-receiver:2.0.21=classpath -org.jetbrains.kotlin:kotlin-stdlib:2.0.21=classpath -org.jetbrains.kotlin:kotlin-tooling-core:2.0.21=classpath -org.jetbrains.kotlin:kotlin-util-io:2.0.21=classpath -org.jetbrains.kotlin:kotlin-util-klib:2.0.21=classpath -org.jetbrains.kotlinx.binary-compatibility-validator:org.jetbrains.kotlinx.binary-compatibility-validator.gradle.plugin:0.18.1=classpath -org.jetbrains.kotlinx:binary-compatibility-validator:0.18.1=classpath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=classpath -org.jetbrains:annotations:13.0=classpath -empty= diff --git a/CHANGELOG.md b/mps-gradle-plugin/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to mps-gradle-plugin/CHANGELOG.md diff --git a/README.md b/mps-gradle-plugin/README.md similarity index 100% rename from README.md rename to mps-gradle-plugin/README.md diff --git a/api/mps-gradle-plugin.api b/mps-gradle-plugin/api/mps-gradle-plugin.api similarity index 100% rename from api/mps-gradle-plugin.api rename to mps-gradle-plugin/api/mps-gradle-plugin.api diff --git a/build.gradle.kts b/mps-gradle-plugin/build.gradle.kts similarity index 94% rename from build.gradle.kts rename to mps-gradle-plugin/build.gradle.kts index 6405cba..c54f721 100644 --- a/build.gradle.kts +++ b/mps-gradle-plugin/build.gradle.kts @@ -1,16 +1,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.KotlinVersion -buildscript { - configurations.classpath { - resolutionStrategy.activateDependencyLocking() - } - - dependencies { - classpath("de.itemis.mps.gradle:git-based-versioning") - } -} - plugins { groovy `java-gradle-plugin` diff --git a/docs/notes/custom-mps-distribution.md b/mps-gradle-plugin/docs/notes/custom-mps-distribution.md similarity index 100% rename from docs/notes/custom-mps-distribution.md rename to mps-gradle-plugin/docs/notes/custom-mps-distribution.md diff --git a/docs/notes/mps-vs-idea-environment.md b/mps-gradle-plugin/docs/notes/mps-vs-idea-environment.md similarity index 100% rename from docs/notes/mps-vs-idea-environment.md rename to mps-gradle-plugin/docs/notes/mps-vs-idea-environment.md diff --git a/docs/tasks/BundleMacosJdk.md b/mps-gradle-plugin/docs/tasks/BundleMacosJdk.md similarity index 100% rename from docs/tasks/BundleMacosJdk.md rename to mps-gradle-plugin/docs/tasks/BundleMacosJdk.md diff --git a/docs/tasks/CreateDmg.md b/mps-gradle-plugin/docs/tasks/CreateDmg.md similarity index 100% rename from docs/tasks/CreateDmg.md rename to mps-gradle-plugin/docs/tasks/CreateDmg.md diff --git a/docs/tasks/GenerateLibrariesXml.md b/mps-gradle-plugin/docs/tasks/GenerateLibrariesXml.md similarity index 100% rename from docs/tasks/GenerateLibrariesXml.md rename to mps-gradle-plugin/docs/tasks/GenerateLibrariesXml.md diff --git a/docs/tasks/MpsCheck.md b/mps-gradle-plugin/docs/tasks/MpsCheck.md similarity index 100% rename from docs/tasks/MpsCheck.md rename to mps-gradle-plugin/docs/tasks/MpsCheck.md diff --git a/docs/tasks/MpsExecute.md b/mps-gradle-plugin/docs/tasks/MpsExecute.md similarity index 100% rename from docs/tasks/MpsExecute.md rename to mps-gradle-plugin/docs/tasks/MpsExecute.md diff --git a/docs/tasks/MpsGenerate.md b/mps-gradle-plugin/docs/tasks/MpsGenerate.md similarity index 100% rename from docs/tasks/MpsGenerate.md rename to mps-gradle-plugin/docs/tasks/MpsGenerate.md diff --git a/docs/tasks/MpsMigrate.md b/mps-gradle-plugin/docs/tasks/MpsMigrate.md similarity index 100% rename from docs/tasks/MpsMigrate.md rename to mps-gradle-plugin/docs/tasks/MpsMigrate.md diff --git a/docs/tasks/Remigrate.md b/mps-gradle-plugin/docs/tasks/Remigrate.md similarity index 100% rename from docs/tasks/Remigrate.md rename to mps-gradle-plugin/docs/tasks/Remigrate.md diff --git a/docs/tasks/RunAntScript.md b/mps-gradle-plugin/docs/tasks/RunAntScript.md similarity index 100% rename from docs/tasks/RunAntScript.md rename to mps-gradle-plugin/docs/tasks/RunAntScript.md diff --git a/gradle.lockfile b/mps-gradle-plugin/gradle.lockfile similarity index 98% rename from gradle.lockfile rename to mps-gradle-plugin/gradle.lockfile index 1b6e38b..7c8e6fe 100644 --- a/gradle.lockfile +++ b/mps-gradle-plugin/gradle.lockfile @@ -1,7 +1,7 @@ # This is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. -de.itemis.mps.build-backends:launcher:2.8.0.167.c51149b=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath +de.itemis.mps.build-backends:launcher:2.8.0.171.f987265=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath junit:junit:4.13.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath net.swiftzer.semver:semver:1.1.2=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath diff --git a/mps-gradle-plugin/settings.gradle.kts b/mps-gradle-plugin/settings.gradle.kts new file mode 100644 index 0000000..81883df --- /dev/null +++ b/mps-gradle-plugin/settings.gradle.kts @@ -0,0 +1,15 @@ +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version ("0.8.0") +} + +dependencyResolutionManagement { + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} + +rootProject.name = "mps-gradle-plugin" + +includeBuild("../git-based-versioning") diff --git a/src/main/groovy/de/itemis/mps/gradle/BundleMacosJdk.groovy b/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/BundleMacosJdk.groovy similarity index 100% rename from src/main/groovy/de/itemis/mps/gradle/BundleMacosJdk.groovy rename to mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/BundleMacosJdk.groovy diff --git a/src/main/groovy/de/itemis/mps/gradle/BundledScripts.groovy b/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/BundledScripts.groovy similarity index 100% rename from src/main/groovy/de/itemis/mps/gradle/BundledScripts.groovy rename to mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/BundledScripts.groovy diff --git a/src/main/groovy/de/itemis/mps/gradle/CreateDmg.groovy b/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/CreateDmg.groovy similarity index 100% rename from src/main/groovy/de/itemis/mps/gradle/CreateDmg.groovy rename to mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/CreateDmg.groovy diff --git a/src/main/groovy/de/itemis/mps/gradle/GenerateLibrariesXml.groovy b/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/GenerateLibrariesXml.groovy similarity index 100% rename from src/main/groovy/de/itemis/mps/gradle/GenerateLibrariesXml.groovy rename to mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/GenerateLibrariesXml.groovy diff --git a/src/main/groovy/de/itemis/mps/gradle/GetMpsInBrowser.groovy b/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/GetMpsInBrowser.groovy similarity index 100% rename from src/main/groovy/de/itemis/mps/gradle/GetMpsInBrowser.groovy rename to mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/GetMpsInBrowser.groovy diff --git a/src/main/groovy/de/itemis/mps/gradle/Pom.groovy b/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/Pom.groovy similarity index 100% rename from src/main/groovy/de/itemis/mps/gradle/Pom.groovy rename to mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/Pom.groovy diff --git a/src/main/kotlin/de/itemis/mps/gradle/BackendConfigurations.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/BackendConfigurations.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/BackendConfigurations.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/BackendConfigurations.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/Common.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/Common.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/Common.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/Common.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/ErrorMessages.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/ErrorMessages.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/ErrorMessages.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/ErrorMessages.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/TaskGroups.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/TaskGroups.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/TaskGroups.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/TaskGroups.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/common.gradle.kts b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/common.gradle.kts similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/common.gradle.kts rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/common.gradle.kts diff --git a/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/Tasks.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/Tasks.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/downloadJBR/Tasks.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/Tasks.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/ToolchainSpecFactory.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/ToolchainSpecFactory.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/downloadJBR/ToolchainSpecFactory.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/ToolchainSpecFactory.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/ExcludedModuleMigration.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/ExcludedModuleMigration.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/tasks/ExcludedModuleMigration.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/ExcludedModuleMigration.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/Libraries.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Libraries.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/tasks/Libraries.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Libraries.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/PluginIds.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/PluginIds.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/tasks/PluginIds.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/PluginIds.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt diff --git a/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt similarity index 100% rename from src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt rename to mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/backend_arguments.kt diff --git a/src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore.pm b/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore.pm similarity index 100% rename from src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore.pm rename to mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore.pm diff --git a/src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore/BuddyAllocator.pm b/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore/BuddyAllocator.pm similarity index 100% rename from src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore/BuddyAllocator.pm rename to mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore/BuddyAllocator.pm diff --git a/src/main/resources/de/itemis/mps/gradle/bundle_macos_jdk.sh b/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/bundle_macos_jdk.sh similarity index 100% rename from src/main/resources/de/itemis/mps/gradle/bundle_macos_jdk.sh rename to mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/bundle_macos_jdk.sh diff --git a/src/main/resources/de/itemis/mps/gradle/mpsdmg.pl b/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpsdmg.pl similarity index 100% rename from src/main/resources/de/itemis/mps/gradle/mpsdmg.pl rename to mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpsdmg.pl diff --git a/src/main/resources/de/itemis/mps/gradle/mpsdmg.sh b/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpsdmg.sh similarity index 100% rename from src/main/resources/de/itemis/mps/gradle/mpsdmg.sh rename to mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpsdmg.sh diff --git a/src/main/resources/de/itemis/mps/gradle/mpssign.sh b/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpssign.sh similarity index 100% rename from src/main/resources/de/itemis/mps/gradle/mpssign.sh rename to mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpssign.sh diff --git a/src/test/kotlin/support/ProjectHelper.kt b/mps-gradle-plugin/src/test/kotlin/support/ProjectHelper.kt similarity index 100% rename from src/test/kotlin/support/ProjectHelper.kt rename to mps-gradle-plugin/src/test/kotlin/support/ProjectHelper.kt diff --git a/src/test/kotlin/test/MpsTaskInterfaceTest.kt b/mps-gradle-plugin/src/test/kotlin/test/MpsTaskInterfaceTest.kt similarity index 100% rename from src/test/kotlin/test/MpsTaskInterfaceTest.kt rename to mps-gradle-plugin/src/test/kotlin/test/MpsTaskInterfaceTest.kt diff --git a/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt b/mps-gradle-plugin/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt similarity index 100% rename from src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt rename to mps-gradle-plugin/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt diff --git a/src/test/kotlin/test/migration/RemigrateTest.kt b/mps-gradle-plugin/src/test/kotlin/test/migration/RemigrateTest.kt similarity index 100% rename from src/test/kotlin/test/migration/RemigrateTest.kt rename to mps-gradle-plugin/src/test/kotlin/test/migration/RemigrateTest.kt diff --git a/src/test/kotlin/test/migration/RunMigrationsTest.kt b/mps-gradle-plugin/src/test/kotlin/test/migration/RunMigrationsTest.kt similarity index 100% rename from src/test/kotlin/test/migration/RunMigrationsTest.kt rename to mps-gradle-plugin/src/test/kotlin/test/migration/RunMigrationsTest.kt diff --git a/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt b/mps-gradle-plugin/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt similarity index 100% rename from src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt rename to mps-gradle-plugin/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt diff --git a/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt b/mps-gradle-plugin/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt similarity index 100% rename from src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt rename to mps-gradle-plugin/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt diff --git a/src/test/kotlin/test/others/GenerateProjectLibrariesXmlTest.kt b/mps-gradle-plugin/src/test/kotlin/test/others/GenerateProjectLibrariesXmlTest.kt similarity index 100% rename from src/test/kotlin/test/others/GenerateProjectLibrariesXmlTest.kt rename to mps-gradle-plugin/src/test/kotlin/test/others/GenerateProjectLibrariesXmlTest.kt diff --git a/src/test/kotlin/test/others/PluginIdsTest.kt b/mps-gradle-plugin/src/test/kotlin/test/others/PluginIdsTest.kt similarity index 100% rename from src/test/kotlin/test/others/PluginIdsTest.kt rename to mps-gradle-plugin/src/test/kotlin/test/others/PluginIdsTest.kt diff --git a/src/test/resources/test-project-with-errors/.mps/.name b/mps-gradle-plugin/src/test/resources/test-project-with-errors/.mps/.name similarity index 100% rename from src/test/resources/test-project-with-errors/.mps/.name rename to mps-gradle-plugin/src/test/resources/test-project-with-errors/.mps/.name diff --git a/src/test/resources/test-project-with-errors/.mps/encodings.xml b/mps-gradle-plugin/src/test/resources/test-project-with-errors/.mps/encodings.xml similarity index 100% rename from src/test/resources/test-project-with-errors/.mps/encodings.xml rename to mps-gradle-plugin/src/test/resources/test-project-with-errors/.mps/encodings.xml diff --git a/src/test/resources/test-project-with-errors/.mps/migration.xml b/mps-gradle-plugin/src/test/resources/test-project-with-errors/.mps/migration.xml similarity index 100% rename from src/test/resources/test-project-with-errors/.mps/migration.xml rename to mps-gradle-plugin/src/test/resources/test-project-with-errors/.mps/migration.xml diff --git a/src/test/resources/test-project-with-errors/.mps/misc.xml b/mps-gradle-plugin/src/test/resources/test-project-with-errors/.mps/misc.xml similarity index 100% rename from src/test/resources/test-project-with-errors/.mps/misc.xml rename to mps-gradle-plugin/src/test/resources/test-project-with-errors/.mps/misc.xml diff --git a/src/test/resources/test-project-with-errors/.mps/modules.xml b/mps-gradle-plugin/src/test/resources/test-project-with-errors/.mps/modules.xml similarity index 100% rename from src/test/resources/test-project-with-errors/.mps/modules.xml rename to mps-gradle-plugin/src/test/resources/test-project-with-errors/.mps/modules.xml diff --git a/src/test/resources/test-project-with-errors/.mps/vcs.xml b/mps-gradle-plugin/src/test/resources/test-project-with-errors/.mps/vcs.xml similarity index 100% rename from src/test/resources/test-project-with-errors/.mps/vcs.xml rename to mps-gradle-plugin/src/test/resources/test-project-with-errors/.mps/vcs.xml diff --git a/src/test/resources/test-project-with-errors/solutions/my.solution.with.errors/models/java.mps b/mps-gradle-plugin/src/test/resources/test-project-with-errors/solutions/my.solution.with.errors/models/java.mps similarity index 100% rename from src/test/resources/test-project-with-errors/solutions/my.solution.with.errors/models/java.mps rename to mps-gradle-plugin/src/test/resources/test-project-with-errors/solutions/my.solution.with.errors/models/java.mps diff --git a/src/test/resources/test-project-with-errors/solutions/my.solution.with.errors/my.solution.with.errors.msd b/mps-gradle-plugin/src/test/resources/test-project-with-errors/solutions/my.solution.with.errors/my.solution.with.errors.msd similarity index 100% rename from src/test/resources/test-project-with-errors/solutions/my.solution.with.errors/my.solution.with.errors.msd rename to mps-gradle-plugin/src/test/resources/test-project-with-errors/solutions/my.solution.with.errors/my.solution.with.errors.msd diff --git a/src/test/resources/test-project-with-errors/solutions/my.solution/models/java.mps b/mps-gradle-plugin/src/test/resources/test-project-with-errors/solutions/my.solution/models/java.mps similarity index 100% rename from src/test/resources/test-project-with-errors/solutions/my.solution/models/java.mps rename to mps-gradle-plugin/src/test/resources/test-project-with-errors/solutions/my.solution/models/java.mps diff --git a/src/test/resources/test-project-with-errors/solutions/my.solution/my.solution.msd b/mps-gradle-plugin/src/test/resources/test-project-with-errors/solutions/my.solution/my.solution.msd similarity index 100% rename from src/test/resources/test-project-with-errors/solutions/my.solution/my.solution.msd rename to mps-gradle-plugin/src/test/resources/test-project-with-errors/solutions/my.solution/my.solution.msd diff --git a/src/test/resources/test-project/.mps/.gitignore b/mps-gradle-plugin/src/test/resources/test-project/.mps/.gitignore similarity index 100% rename from src/test/resources/test-project/.mps/.gitignore rename to mps-gradle-plugin/src/test/resources/test-project/.mps/.gitignore diff --git a/src/test/resources/test-project/.mps/migration.xml b/mps-gradle-plugin/src/test/resources/test-project/.mps/migration.xml similarity index 100% rename from src/test/resources/test-project/.mps/migration.xml rename to mps-gradle-plugin/src/test/resources/test-project/.mps/migration.xml diff --git a/src/test/resources/test-project/.mps/misc.xml b/mps-gradle-plugin/src/test/resources/test-project/.mps/misc.xml similarity index 100% rename from src/test/resources/test-project/.mps/misc.xml rename to mps-gradle-plugin/src/test/resources/test-project/.mps/misc.xml diff --git a/src/test/resources/test-project/.mps/modules.xml b/mps-gradle-plugin/src/test/resources/test-project/.mps/modules.xml similarity index 100% rename from src/test/resources/test-project/.mps/modules.xml rename to mps-gradle-plugin/src/test/resources/test-project/.mps/modules.xml diff --git a/src/test/resources/test-project/.mps/vcs.xml b/mps-gradle-plugin/src/test/resources/test-project/.mps/vcs.xml similarity index 100% rename from src/test/resources/test-project/.mps/vcs.xml rename to mps-gradle-plugin/src/test/resources/test-project/.mps/vcs.xml diff --git a/src/test/resources/test-project/solutions/NewSolution/NewSolution.msd b/mps-gradle-plugin/src/test/resources/test-project/solutions/NewSolution/NewSolution.msd similarity index 100% rename from src/test/resources/test-project/solutions/NewSolution/NewSolution.msd rename to mps-gradle-plugin/src/test/resources/test-project/solutions/NewSolution/NewSolution.msd diff --git a/src/test/resources/test-project/solutions/NewSolution/models/NewSolution.myModel.mps b/mps-gradle-plugin/src/test/resources/test-project/solutions/NewSolution/models/NewSolution.myModel.mps similarity index 100% rename from src/test/resources/test-project/solutions/NewSolution/models/NewSolution.myModel.mps rename to mps-gradle-plugin/src/test/resources/test-project/solutions/NewSolution/models/NewSolution.myModel.mps diff --git a/settings.gradle.kts b/settings.gradle.kts index a400c38..9c2d34a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -9,3 +9,5 @@ plugins { rootProject.name = "mps-gradle-plugin" includeBuild("git-based-versioning") + +includeBuild("mps-gradle-plugin") From f80262d51523c5e6b542d0285d11a15e17d1a6d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 16:20:30 +0200 Subject: [PATCH 23/44] Extract MpsTask and MpsProjectTask into :mps-gradle-plugin-api included build Co-Authored-By: Claude Opus 4.7 (1M context) --- .../api/mps-gradle-plugin-api.api | 13 +++ mps-gradle-plugin-api/build.gradle.kts | 92 +++++++++++++++++++ mps-gradle-plugin-api/gradle.lockfile | 29 ++++++ mps-gradle-plugin-api/settings.gradle.kts | 13 +++ .../itemis/mps/gradle/tasks/MpsProjectTask.kt | 0 .../de/itemis/mps/gradle/tasks/MpsTask.kt | 0 mps-gradle-plugin/api/mps-gradle-plugin.api | 13 --- mps-gradle-plugin/build.gradle.kts | 1 + mps-gradle-plugin/settings.gradle.kts | 2 + settings.gradle.kts | 2 + 10 files changed, 152 insertions(+), 13 deletions(-) create mode 100644 mps-gradle-plugin-api/api/mps-gradle-plugin-api.api create mode 100644 mps-gradle-plugin-api/build.gradle.kts create mode 100644 mps-gradle-plugin-api/gradle.lockfile create mode 100644 mps-gradle-plugin-api/settings.gradle.kts rename {mps-gradle-plugin => mps-gradle-plugin-api}/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt (100%) rename {mps-gradle-plugin => mps-gradle-plugin-api}/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt (100%) diff --git a/mps-gradle-plugin-api/api/mps-gradle-plugin-api.api b/mps-gradle-plugin-api/api/mps-gradle-plugin-api.api new file mode 100644 index 0000000..c9b9977 --- /dev/null +++ b/mps-gradle-plugin-api/api/mps-gradle-plugin-api.api @@ -0,0 +1,13 @@ +public abstract interface class de/itemis/mps/gradle/tasks/MpsProjectTask : de/itemis/mps/gradle/tasks/MpsTask { + public abstract fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; + public abstract fun getLogLevel ()Lorg/gradle/api/provider/Property; + public abstract fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; + public abstract fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; +} + +public abstract interface class de/itemis/mps/gradle/tasks/MpsTask : org/gradle/api/Task { + public abstract fun getJavaLauncher ()Lorg/gradle/api/provider/Property; + public abstract fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; + public abstract fun getMpsVersion ()Lorg/gradle/api/provider/Property; +} + diff --git a/mps-gradle-plugin-api/build.gradle.kts b/mps-gradle-plugin-api/build.gradle.kts new file mode 100644 index 0000000..9eb5eb1 --- /dev/null +++ b/mps-gradle-plugin-api/build.gradle.kts @@ -0,0 +1,92 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion + +plugins { + `kotlin-dsl` + `maven-publish` + alias(libs.plugins.kotlin.compatibility.validator) +} + +group = "de.itemis.mps" + +version = "1.0.0-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencyLocking { + lockAllConfigurations() +} + +publishing { + repositories { + val isSnapshot = project.version.toString().endsWith("SNAPSHOT") + if (project.hasProperty("artifacts.itemis.cloud.user") && project.hasProperty("artifacts.itemis.cloud.pw")) { + maven { + name = "itemisCloud" + if (isSnapshot) { + url = uri("https://artifacts.itemis.cloud/repository/maven-mps-snapshots/") + } else { + url = uri("https://artifacts.itemis.cloud/repository/maven-mps-releases/") + } + credentials { + username = project.findProperty("artifacts.itemis.cloud.user") as String? + password = project.findProperty("artifacts.itemis.cloud.pw") as String? + } + } + } + + if (!isSnapshot && project.hasProperty("gpr.token")) { + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/mbeddr/mps-gradle-plugin") + credentials { + username = project.findProperty("gpr.user") as String? + password = project.findProperty("gpr.token") as String? + } + } + } + } + + publications.withType().configureEach { + versionMapping { + allVariants { + fromResolutionResult() + } + } + pom { + url = "https://github.com/mbeddr/mps-gradle-plugin" + licenses { + license { + name = "The Apache License, Version 2.0" + url = "https://www.apache.org/licenses/LICENSE-2.0.txt" + } + } + scm { + connection = "scm:git:git://github.com/mbeddr/mps-gradle-plugin.git" + developerConnection = "scm:git:ssh://github.com/mbeddr/mps-gradle-plugin.git" + url = "https://github.com/mbeddr/mps-gradle-plugin" + } + } + } +} + +java { + targetCompatibility = JavaVersion.VERSION_11 + withSourcesJar() +} + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.fromTarget(libs.versions.kotlinJvmTarget.get()) + apiVersion = KotlinVersion.fromVersion(libs.versions.kotlinApi.get()) + allWarningsAsErrors = true + } +} + +tasks.register("setTeamCityBuildNumber") { + doLast { + println("##teamcity[buildNumber '$version']") + } +} diff --git a/mps-gradle-plugin-api/gradle.lockfile b/mps-gradle-plugin-api/gradle.lockfile new file mode 100644 index 0000000..87cf800 --- /dev/null +++ b/mps-gradle-plugin-api/gradle.lockfile @@ -0,0 +1,29 @@ +# This is a Gradle generated file for dependency locking. +# Manual edits can break the build and are not advised. +# This file is expected to be part of source control. +org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-assignment-compiler-plugin-embeddable:2.0.21=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-build-common:2.0.21=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-build-tools-api:2.0.21=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-build-tools-impl:2.0.21=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-compiler-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-compiler-runner:2.0.21=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-daemon-client:2.0.21=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-daemon-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:2.0.21=kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-metadata-jvm:2.0.21=bcv-rt-jvm-cp-resolver +org.jetbrains.kotlin:kotlin-native-prebuilt:2.0.21=kotlinNativeBundleConfiguration +org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-reflect:2.0.21=compileClasspath,compileOnlyDependenciesMetadata,embeddedKotlin,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-sam-with-receiver-compiler-plugin-embeddable:2.0.21=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-script-runtime:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-scripting-common:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-scripting-jvm:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-stdlib:2.0.21=bcv-rt-jvm-cp-resolver,compileClasspath,compileOnlyDependenciesMetadata,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains:annotations:13.0=bcv-rt-jvm-cp-resolver,compileClasspath,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testRuntimeClasspath +org.ow2.asm:asm-tree:9.6=bcv-rt-jvm-cp-resolver +org.ow2.asm:asm:9.6=bcv-rt-jvm-cp-resolver +empty=annotationProcessor,apiDependenciesMetadata,implementationDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDefExtensions,runtimeClasspath,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDefExtensions diff --git a/mps-gradle-plugin-api/settings.gradle.kts b/mps-gradle-plugin-api/settings.gradle.kts new file mode 100644 index 0000000..70ebd33 --- /dev/null +++ b/mps-gradle-plugin-api/settings.gradle.kts @@ -0,0 +1,13 @@ +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version ("0.8.0") +} + +dependencyResolutionManagement { + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} + +rootProject.name = "mps-gradle-plugin-api" diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt b/mps-gradle-plugin-api/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt similarity index 100% rename from mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt rename to mps-gradle-plugin-api/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt b/mps-gradle-plugin-api/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt similarity index 100% rename from mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt rename to mps-gradle-plugin-api/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt diff --git a/mps-gradle-plugin/api/mps-gradle-plugin.api b/mps-gradle-plugin/api/mps-gradle-plugin.api index e26ff80..b55a0d2 100644 --- a/mps-gradle-plugin/api/mps-gradle-plugin.api +++ b/mps-gradle-plugin/api/mps-gradle-plugin.api @@ -239,19 +239,6 @@ public abstract class de/itemis/mps/gradle/tasks/MpsMigrate : org/gradle/api/Def public final fun getProjectLocations ()Lorg/gradle/api/file/ConfigurableFileCollection; } -public abstract interface class de/itemis/mps/gradle/tasks/MpsProjectTask : de/itemis/mps/gradle/tasks/MpsTask { - public abstract fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; - public abstract fun getLogLevel ()Lorg/gradle/api/provider/Property; - public abstract fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; - public abstract fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; -} - -public abstract interface class de/itemis/mps/gradle/tasks/MpsTask : org/gradle/api/Task { - public abstract fun getJavaLauncher ()Lorg/gradle/api/provider/Property; - public abstract fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; - public abstract fun getMpsVersion ()Lorg/gradle/api/provider/Property; -} - public class de/itemis/mps/gradle/tasks/Remigrate : org/gradle/api/tasks/JavaExec, de/itemis/mps/gradle/tasks/MpsProjectTask { public fun (Lorg/gradle/api/model/ObjectFactory;Lorg/gradle/api/provider/ProviderFactory;)V public final fun excludeModuleMigration (Ljava/lang/String;I)V diff --git a/mps-gradle-plugin/build.gradle.kts b/mps-gradle-plugin/build.gradle.kts index c54f721..80fa89e 100644 --- a/mps-gradle-plugin/build.gradle.kts +++ b/mps-gradle-plugin/build.gradle.kts @@ -26,6 +26,7 @@ dependencyLocking { dependencies { api(libs.itemis.gradle.git.based.versioning) + api("de.itemis.mps:mps-gradle-plugin-api") implementation(libs.kotlin.stdlib) implementation(libs.swiftzer.semver) implementation(libs.itemis.gradle.build.backends.launcher) diff --git a/mps-gradle-plugin/settings.gradle.kts b/mps-gradle-plugin/settings.gradle.kts index 81883df..75c4133 100644 --- a/mps-gradle-plugin/settings.gradle.kts +++ b/mps-gradle-plugin/settings.gradle.kts @@ -13,3 +13,5 @@ dependencyResolutionManagement { rootProject.name = "mps-gradle-plugin" includeBuild("../git-based-versioning") + +includeBuild("../mps-gradle-plugin-api") diff --git a/settings.gradle.kts b/settings.gradle.kts index 9c2d34a..eb4570d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,4 +10,6 @@ rootProject.name = "mps-gradle-plugin" includeBuild("git-based-versioning") +includeBuild("mps-gradle-plugin-api") + includeBuild("mps-gradle-plugin") From d47b0a4d26ae0905286ade116aaf6161031185e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 16:29:01 +0200 Subject: [PATCH 24/44] Fix flaky RemigrateTest by applying foojay resolver in its test settings Remigrate always requires a JDK 11 toolchain (its MpsBackendBuilder sets javaLauncher from mpsVersion), but the test's settings.gradle.kts did not apply the foojay-resolver-convention plugin. It relied on sibling Mps*TaskTest runs to provision JDK 11 into the shared TestKit Gradle home. Under parallel test execution, Remigrate could start before any foojay-enabled sibling finished provisioning and then fail with "Toolchain download repositories have not been configured." --- .../src/test/kotlin/test/migration/RemigrateTest.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mps-gradle-plugin/src/test/kotlin/test/migration/RemigrateTest.kt b/mps-gradle-plugin/src/test/kotlin/test/migration/RemigrateTest.kt index a80332a..b791299 100644 --- a/mps-gradle-plugin/src/test/kotlin/test/migration/RemigrateTest.kt +++ b/mps-gradle-plugin/src/test/kotlin/test/migration/RemigrateTest.kt @@ -23,6 +23,9 @@ class RemigrateTest { settingsFile = testProjectDir.newFile("settings.gradle.kts") settingsFile.writeText( """ + plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version ("0.7.0") + } rootProject.name = "hello-world" """.trimIndent() ) From 2ff3304aa9be3128afc19fad2d8828ef50f769cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 16:57:58 +0200 Subject: [PATCH 25/44] Add Renovate config with custom managers for versions in test sources Pins in Kotlin test files (foojay-resolver-convention plugin, com.jetbrains:mps distribution) are covered via customManagers so they track upstream releases alongside the main build. forkProcessing is enabled since this repo is a fork. Co-Authored-By: Claude Opus 4.7 (1M context) --- renovate.json | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 renovate.json diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..ef87c82 --- /dev/null +++ b/renovate.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ], + "forkProcessing": "enabled", + "customManagers": [ + { + "customType": "regex", + "description": "Update foojay-resolver-convention plugin pinned inside Kotlin test sources (used in generated Gradle scripts).", + "managerFilePatterns": [ + "/^mps-gradle-plugin/src/test/kotlin/.*\\.kt$/" + ], + "matchStrings": [ + "id\\(\"org\\.gradle\\.toolchains\\.foojay-resolver-convention\"\\)\\s*version\\s*\\(\"(?[^\"]+)\"\\)" + ], + "depNameTemplate": "org.gradle.toolchains.foojay-resolver-convention", + "packageNameTemplate": "org.gradle.toolchains.foojay-resolver-convention:org.gradle.toolchains.foojay-resolver-convention.gradle.plugin", + "datasourceTemplate": "maven", + "registryUrlTemplate": "https://plugins.gradle.org/m2/" + }, + { + "customType": "regex", + "description": "Update com.jetbrains:mps versions embedded in Kotlin test sources (used in generated Gradle scripts).", + "managerFilePatterns": [ + "/^mps-gradle-plugin/src/test/kotlin/.*\\.kt$/" + ], + "matchStrings": [ + "mps\\(\"com\\.jetbrains:mps:(?[^\"]+)\"\\)" + ], + "depNameTemplate": "com.jetbrains:mps", + "datasourceTemplate": "maven" + } + ] +} From fe64e76f61a69d7f489ad0226b1b73cea0e79ea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 17:36:55 +0200 Subject: [PATCH 26/44] Remove macOS packaging tasks and DownloadJbrForPlatform Drops CreateDmg, BundleMacosJdk (with their bundled shell/perl scripts and docs), plus DownloadJbrForPlatform and its helper ToolchainSpecFactory. macOS installer building is no longer in scope for this plugin; JBR toolchain resolution is better served by specificlanguages/mps-gradle-plugin's jbr-toolchain subproject. Co-Authored-By: Claude Opus 4.7 (1M context) --- mps-gradle-plugin/CHANGELOG.md | 7 +- mps-gradle-plugin/README.md | 8 - mps-gradle-plugin/api/mps-gradle-plugin.api | 61 -- .../docs/tasks/BundleMacosJdk.md | 33 - mps-gradle-plugin/docs/tasks/CreateDmg.md | 46 - .../itemis/mps/gradle/BundleMacosJdk.groovy | 76 -- .../itemis/mps/gradle/BundledScripts.groovy | 26 - .../de/itemis/mps/gradle/CreateDmg.groovy | 106 --- .../de/itemis/mps/gradle/downloadJBR/Tasks.kt | 56 -- .../downloadJBR/ToolchainSpecFactory.kt | 37 - .../itemis/mps/gradle/Mac/Finder/DSStore.pm | 733 ---------------- .../Mac/Finder/DSStore/BuddyAllocator.pm | 783 ------------------ .../de/itemis/mps/gradle/bundle_macos_jdk.sh | 80 -- .../resources/de/itemis/mps/gradle/mpsdmg.pl | 28 - .../resources/de/itemis/mps/gradle/mpsdmg.sh | 65 -- .../resources/de/itemis/mps/gradle/mpssign.sh | 109 --- 16 files changed, 6 insertions(+), 2248 deletions(-) delete mode 100644 mps-gradle-plugin/docs/tasks/BundleMacosJdk.md delete mode 100644 mps-gradle-plugin/docs/tasks/CreateDmg.md delete mode 100644 mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/BundleMacosJdk.groovy delete mode 100644 mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/BundledScripts.groovy delete mode 100644 mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/CreateDmg.groovy delete mode 100644 mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/Tasks.kt delete mode 100644 mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/ToolchainSpecFactory.kt delete mode 100644 mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore.pm delete mode 100644 mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore/BuddyAllocator.pm delete mode 100755 mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/bundle_macos_jdk.sh delete mode 100644 mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpsdmg.pl delete mode 100755 mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpsdmg.sh delete mode 100755 mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpssign.sh diff --git a/mps-gradle-plugin/CHANGELOG.md b/mps-gradle-plugin/CHANGELOG.md index e8669f5..c7f322e 100644 --- a/mps-gradle-plugin/CHANGELOG.md +++ b/mps-gradle-plugin/CHANGELOG.md @@ -7,7 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed - Old plugins (`generate-models`, `modelcheck`, `run-migrations`, `download-jbr`) have been removed. Use the task types - (`MpsGenerate`, `MpsCheck`, `MpsMigrate`, `Remigrate`, `DownloadJbrForPlatform`) directly instead. + (`MpsGenerate`, `MpsCheck`, `MpsMigrate`, `Remigrate`) directly instead. +- `CreateDmg` and `BundleMacosJdk` tasks have been removed. Building macOS installers is no longer in scope for this + plugin. +- `DownloadJbrForPlatform` task and the `downloadJBR` package have been removed. Use the + [jbr-toolchain plugin](https://github.com/specificlanguages/mps-gradle-plugin/tree/master/subprojects/jbr-toolchain) + if JetBrains Runtime is required. ### Added diff --git a/mps-gradle-plugin/README.md b/mps-gradle-plugin/README.md index a9d4523..8577db3 100644 --- a/mps-gradle-plugin/README.md +++ b/mps-gradle-plugin/README.md @@ -37,8 +37,6 @@ reproducibility. Tasks: * [RunAntScript](docs/tasks/RunAntScript.md) -- run an MPS-generated Ant script. -* [CreateDmg](docs/tasks/CreateDmg.md) -- (macOS only) create a .dmg installer. -* [BundleMacosJdk](docs/tasks/BundleMacosJdk.md) -- (Linux/macOS) create a .tar.gz by combining an RCP artifact and a JDK. * [GenerateLibrariesXml](docs/tasks/GenerateLibrariesXml.md) -- generate a `.mps/libraries.xml` file from property files. * [MpsCheck](docs/tasks/MpsCheck.md) -- check (a subset of) models in a project. * [MpsExecute](docs/tasks/MpsExecute.md) -- execute a specified method in a generated class in the context of a running @@ -47,9 +45,3 @@ Tasks: build model. * [MpsMigrate](docs/tasks/MpsMigrate.md) -- Run pending migrations on one or several MPS projects. -Plugins: - -* [generate](docs/plugins/generate.md) -- Deprecated. Generate (a subset of) models in a project without the need for a MPS - build model. -* [modelcheck/checkmodels](docs/plugins/modelcheck.md) -- Deprecated. Check (a subset of) models in a project. -* [download-jbr/downloadJbr](docs/plugins/download-jbr.md) -- Download JetBrains Runtime. diff --git a/mps-gradle-plugin/api/mps-gradle-plugin.api b/mps-gradle-plugin/api/mps-gradle-plugin.api index b55a0d2..003b1ac 100644 --- a/mps-gradle-plugin/api/mps-gradle-plugin.api +++ b/mps-gradle-plugin/api/mps-gradle-plugin.api @@ -2,33 +2,6 @@ public abstract class de/itemis/mps/gradle/BuildLanguages : de/itemis/mps/gradle public fun ()V } -public class de/itemis/mps/gradle/BundleMacosJdk : org/gradle/api/DefaultTask, groovy/lang/GroovyObject { - public static synthetic field __$stMC Z - protected synthetic fun $getStaticMetaClass ()Lgroovy/lang/MetaClass; - public fun ()V - public fun build ()Ljava/lang/Object; - public fun getJdk ()Ljava/io/File; - public fun getJdkDirname ()Ljava/lang/String; - public fun getMetaClass ()Lgroovy/lang/MetaClass; - public fun getOutputFile ()Ljava/io/File; - public fun getRcpArtifact ()Ljava/io/File; - public fun setJdk (Ljava/lang/Object;)Ljava/lang/Object; - public fun setJdkDependency (Ljava/lang/Object;)Ljava/lang/Object; - public fun setJdkDirname (Ljava/lang/String;)Ljava/lang/Object; - public fun setMetaClass (Lgroovy/lang/MetaClass;)V - public fun setOutputFile (Ljava/lang/Object;)Ljava/lang/Object; - public fun setRcpArtifact (Ljava/lang/Object;)Ljava/lang/Object; -} - -public class de/itemis/mps/gradle/BundledScripts : groovy/lang/GroovyObject { - public static synthetic field __$stMC Z - protected synthetic fun $getStaticMetaClass ()Lgroovy/lang/MetaClass; - public fun ()V - public static fun extractScriptsToDir (Ljava/io/File;[Ljava/lang/String;)V - public fun getMetaClass ()Lgroovy/lang/MetaClass; - public fun setMetaClass (Lgroovy/lang/MetaClass;)V -} - public final class de/itemis/mps/gradle/CommonKt { public static final field MPS_BUILD_BACKENDS_VERSION Ljava/lang/String; } @@ -39,30 +12,6 @@ public final class de/itemis/mps/gradle/CommonPlugin : org/gradle/api/Plugin { public fun apply (Lorg/gradle/api/Project;)V } -public class de/itemis/mps/gradle/CreateDmg : org/gradle/api/DefaultTask, groovy/lang/GroovyObject { - public static synthetic field __$stMC Z - protected synthetic fun $getStaticMetaClass ()Lgroovy/lang/MetaClass; - public fun ()V - public fun build ()Ljava/lang/Object; - public fun getBackgroundImage ()Ljava/io/File; - public fun getDmgFile ()Ljava/io/File; - public fun getJdk ()Ljava/io/File; - public fun getMetaClass ()Lgroovy/lang/MetaClass; - public fun getRcpArtifact ()Ljava/io/File; - public fun getSignIdentity ()Ljava/lang/String; - public fun getSignKeyChain ()Ljava/io/File; - public fun getSignKeyChainPassword ()Ljava/lang/String; - public fun setBackgroundImage (Ljava/lang/Object;)Ljava/lang/Object; - public fun setDmgFile (Ljava/lang/Object;)Ljava/lang/Object; - public fun setJdk (Ljava/lang/Object;)Ljava/lang/Object; - public fun setJdkDependency (Ljava/lang/Object;)Ljava/lang/Object; - public fun setMetaClass (Lgroovy/lang/MetaClass;)V - public fun setRcpArtifact (Ljava/lang/Object;)Ljava/lang/Object; - public fun setSignIdentity (Ljava/lang/String;)V - public fun setSignKeyChain (Ljava/lang/Object;)Ljava/lang/Object; - public fun setSignKeyChainPassword (Ljava/lang/String;)V -} - public final class de/itemis/mps/gradle/EnvironmentKind : java/lang/Enum { public static final field IDEA Lde/itemis/mps/gradle/EnvironmentKind; public static final field MPS Lde/itemis/mps/gradle/EnvironmentKind; @@ -137,16 +86,6 @@ public abstract class de/itemis/mps/gradle/TestLanguages : de/itemis/mps/gradle/ public fun ()V } -public class de/itemis/mps/gradle/downloadJBR/DownloadJbrForPlatform : org/gradle/api/DefaultTask { - public fun (Lorg/gradle/api/model/ObjectFactory;Lorg/gradle/jvm/toolchain/JavaToolchainService;)V - public final fun getJavaExecutable ()Ljava/io/File; - public final fun getJavaLauncher ()Lorg/gradle/api/provider/Provider; - public final fun getJbrDir ()Ljava/io/File; - public final fun getToolchainSpec ()Lorg/gradle/api/provider/Provider; - public final fun setJavaExecutable (Ljava/io/File;)V - public final fun setJbrDir (Ljava/io/File;)V -} - public final class de/itemis/mps/gradle/tasks/ExcludedModuleMigration { public fun (Ljava/lang/String;I)V public final fun component1 ()Ljava/lang/String; diff --git a/mps-gradle-plugin/docs/tasks/BundleMacosJdk.md b/mps-gradle-plugin/docs/tasks/BundleMacosJdk.md deleted file mode 100644 index b9f940e..0000000 --- a/mps-gradle-plugin/docs/tasks/BundleMacosJdk.md +++ /dev/null @@ -1,33 +0,0 @@ -## BundleMacosJdk - -(Linux/macOS) Creates a .tar.gz by combining an RCP artifact and a JDK. -This task is intended as a substitute for the macOS-specific CreateDmg -task. - -### Usage - -``` -task bundleMacosJdk(type: de.itemis.mps.gradle.BundleMacosJdk) { - rcpArtifact file('path/to/RCP.tgz') - - jdkDependency "com.jetbrains.jdk:jdk:${jdkVersion}:osx_x64@tgz" - // -or - - jdk file('path/to/jdk.tgz') - - outputFile file('output.tar.gz') -} -``` - -Parameters: -* `rcpArtifact` - the path to the RCP artifact produced by a build script. -* `jdkDependency` - the coordinates of a JDK in case it's available in - a repository and can be resolved as a Gradle dependency. -* `jdk` - the path to a JDK .tgz file. -* `outputFile` - the path and file name of the output gzipped tar archive. - -### Operation - -The task unpacks `rcpArtifact` into a temporary directory, unpacks -the JDK given by `jdkDependency`/`jdk` under the `jre` subdirectory of -the unpacked RCP artifact, fixes file permissions and creates missing -symlinks. Finally, the file is repackaged again as tar/gzip. diff --git a/mps-gradle-plugin/docs/tasks/CreateDmg.md b/mps-gradle-plugin/docs/tasks/CreateDmg.md deleted file mode 100644 index 94d1106..0000000 --- a/mps-gradle-plugin/docs/tasks/CreateDmg.md +++ /dev/null @@ -1,46 +0,0 @@ -## CreateDmg - -(macOS only) Creates a .dmg installer by combining an RCP artifact (as -created by an MPS-generated Ant script), a JDK, and a background image. - -### Usage - -``` -task buildDmg(type: de.itemis.mps.gradle.CreateDmg) { - rcpArtifact file('path/to/RCP.tgz') - - jdkDependency "com.jetbrains.jdk:jdk:${jdkVersion}:osx_x64@tgz" - // -or - - jdk file('path/to/jdk.tgz') - - backgroundImage file('path/to/background.png') - dmgFile file('output.dmg') - - signKeyChain file("/path/to/my.keychain-db") - - signKeyChainPassword "my.keychain-db-password" - - signIdentity "my Application ID Name" -} -``` - -Parameters: -* `rcpArtifact` - the path to the RCP artifact produced by a build script. -* `jdkDependency` - the coordinates of a JDK in case it's available in - a repository and can be resolved as a Gradle dependency. -* `jdk` - the path to a JDK .tgz file. -* `backgroundImage` - the path to the background image. -* `dmgFile` - the path and file name of the output DMG image. Must end - with `.dmg`. -* `signKeyChain (optional)` - the path and file name of the keychain which contains a code signing certificate. -* `signKeyChainPassword (optional)` - the password which should be used to unlock the keychain. -* `signIdentity (optional)` - the application ID of the code signing certificate. - -### Operation - -The task unpacks `rcpArtifact` into a temporary directory, unpacks -the JDK given by `jdkDependency`/`jdk` under the `jre` subdirectory of -the unpacked RCP artifact, fixes file permissions and creates missing -symlinks. If the additional properties for code signing (`signKeyChain`, `signKeyChainPassword`, `signIdentity`) are defined, -the application will be signed with the given certificate. Afterwards a DMG image is created and its layout is configured using the -background image. Finally, the DMG is copied to `dmgFile`. diff --git a/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/BundleMacosJdk.groovy b/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/BundleMacosJdk.groovy deleted file mode 100644 index 1553c55..0000000 --- a/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/BundleMacosJdk.groovy +++ /dev/null @@ -1,76 +0,0 @@ -package de.itemis.mps.gradle - -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException -import org.gradle.api.artifacts.Dependency -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.Optional -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction - -class BundleMacosJdk extends DefaultTask { - @InputFile - File rcpArtifact - - @Optional @Input - String jdkDirname = "jre" - - @InputFile - File jdk - - @OutputFile - File outputFile - - def setRcpArtifact(Object file) { - this.rcpArtifact = project.file(file) - } - - def setJdkDirname(String dirname) { - this.jdkDirname = dirname - } - - def setJdk(Object file) { - this.jdk = project.file(file) - } - - /** - * Sets the {@link #jdk} property from a dependency, given as either a {@link Dependency} object or in dependency - * notation. - */ - def setJdkDependency(Object jdkDependency) { - Dependency dep = project.dependencies.create(jdkDependency) - def files = project.configurations.detachedConfiguration(dep).resolve() - if (files.size() != 1) { - throw new GradleException( - "Expected a single file for jdkDependency '$jdkDependency', got ${files.size()} files") - } - this.jdk = files.first() - } - - def setOutputFile(Object file) { - this.outputFile = project.file(file) - } - - @TaskAction - def build() { - project.logger.lifecycle("The jdkDirname: ${jdkDirname}") - File scriptsDir = File.createTempDir() - File tmpDir = File.createTempDir() - try { - String scriptName = 'bundle_macos_jdk.sh' - BundledScripts.extractScriptsToDir(scriptsDir, scriptName) - project.exec { - executable new File(scriptsDir, scriptName) - args rcpArtifact, tmpDir, jdkDirname, jdk, outputFile - workingDir scriptsDir - } - } finally { - // Do not use File.deleteDir() because it follows symlinks! - // (e.g. the symlink to /Applications inside tmpDir) - project.exec { - commandLine 'rm', '-rf', scriptsDir, tmpDir - } - } - } -} diff --git a/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/BundledScripts.groovy b/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/BundledScripts.groovy deleted file mode 100644 index 6ca62f1..0000000 --- a/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/BundledScripts.groovy +++ /dev/null @@ -1,26 +0,0 @@ -package de.itemis.mps.gradle - -import org.gradle.api.GradleException - -import java.nio.file.Files -import java.nio.file.attribute.PosixFilePermissions - -class BundledScripts { - static void extractScriptsToDir(File dir, String... scriptNames) { - def rwxPermissions = PosixFilePermissions.fromString("rwx------") - - for (name in scriptNames) { - File file = new File(dir, name) - if (!file.parentFile.isDirectory() && ! file.parentFile.mkdirs()) { - throw new GradleException("Could not create directory " + file.parentFile) - } - InputStream resourceStream = BundledScripts.class.getResourceAsStream(name) - if (resourceStream == null) { - throw new IllegalArgumentException("Resource ${name} was not found") - } - - resourceStream.withStream { is -> file.newOutputStream().withStream { os -> os << is } } - Files.setPosixFilePermissions(file.toPath(), rwxPermissions) - } - } -} diff --git a/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/CreateDmg.groovy b/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/CreateDmg.groovy deleted file mode 100644 index b0dc195..0000000 --- a/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/CreateDmg.groovy +++ /dev/null @@ -1,106 +0,0 @@ -package de.itemis.mps.gradle - -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException -import org.gradle.api.artifacts.Dependency -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction -import org.gradle.api.tasks.Optional - -class CreateDmg extends DefaultTask { - @InputFile - File rcpArtifact - - @InputFile - File backgroundImage - - @InputFile - File jdk - - @OutputFile - File dmgFile - - @Optional @Input - String signKeyChainPassword - - @Optional @Input - String signIdentity - - @InputFile @Optional - File signKeyChain - - def setSignKeyChain(Object file) { - this.signKeyChain = project.file(file) - } - - def setRcpArtifact(Object file) { - this.rcpArtifact = project.file(file) - } - - def setBackgroundImage(Object file) { - this.backgroundImage = project.file(file) - } - - def setJdk(Object file) { - this.jdk = project.file(file) - } - - /** - * Sets the {@link #jdk} property from a dependency, given as either a {@link Dependency} object or in dependency - * notation. - */ - def setJdkDependency(Object jdkDependency) { - Dependency dep = project.dependencies.create(jdkDependency) - def files = project.configurations.detachedConfiguration(dep).resolve() - if (files.size() != 1) { - throw new GradleException( - "Expected a single file for jdkDependency '$jdkDependency', got ${files.size()} files") - } - this.jdk = files.first() - } - - def setDmgFile(Object file) { - this.dmgFile = project.file(file) - if (dmgFile != null && !dmgFile.name.endsWith(".dmg")) { - throw new GradleException("Value of dmgFile must end with .dmg but was $dmgFile") - } - } - - @TaskAction - def build() { - String[] scripts = ['mpssign.sh', 'mpsdmg.sh', 'mpsdmg.pl', - 'Mac/Finder/DSStore/BuddyAllocator.pm', 'Mac/Finder/DSStore.pm'] - File scriptsDir = File.createTempDir() - File dmgDir = File.createTempDir() - def signingInfo = [signKeyChainPassword, signKeyChain, signIdentity] - try { - BundledScripts.extractScriptsToDir(scriptsDir, scripts) - project.exec { - executable new File(scriptsDir, 'mpssign.sh') - - if(signingInfo.every {it != null}) { - args '-r', rcpArtifact, '-o', dmgDir, '-j', jdk, '-p', signKeyChainPassword, '-k', signKeyChain, '-i', signIdentity - }else if (signingInfo.every {it == null}){ - args '-r', rcpArtifact, '-o', dmgDir, '-j', jdk - }else{ - throw new IllegalArgumentException("Not all signing paramters set. signKeyChain: ${getSigningInfo[1]}, signIdentity: ${getSigningInfo[2]} and signKeyChainPassword needs to be set. ") - } - workingDir scriptsDir - } - project.exec { - executable new File(scriptsDir, 'mpsdmg.sh') - args dmgDir, dmgFile, backgroundImage - workingDir scriptsDir - } - } finally { - // Do not use File.deleteDir() because it follows symlinks! - // (e.g. the symlink to /Applications inside dmgDir) - project.exec { - commandLine 'rm', '-rf', scriptsDir, dmgDir - } - } - } - -} diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/Tasks.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/Tasks.kt deleted file mode 100644 index 709ce2c..0000000 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/Tasks.kt +++ /dev/null @@ -1,56 +0,0 @@ -package de.itemis.mps.gradle.downloadJBR - -import org.gradle.api.DefaultTask -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.model.ObjectFactory -import org.gradle.api.provider.Provider -import org.gradle.api.tasks.* -import org.gradle.jvm.toolchain.JavaLauncher -import org.gradle.jvm.toolchain.JavaToolchainService -import org.gradle.jvm.toolchain.JavaToolchainSpec -import org.gradle.jvm.toolchain.internal.SpecificInstallationToolchainSpec -import java.io.File -import javax.inject.Inject - -open class DownloadJbrForPlatform @Inject constructor( - objects: ObjectFactory, - private val javaToolchainService: JavaToolchainService -) : DefaultTask() { - - private val toolchainSpecFactory = objects.newInstance(ToolchainSpecFactory::class.java) - - @get:Internal - internal val jbrDirProperty: DirectoryProperty = objects.directoryProperty() - - @get:Internal - var jbrDir : File - get() = jbrDirProperty.get().asFile - set(value) { - jbrDirProperty.set(value) - } - - @get:Internal - internal val javaExecutableProperty: RegularFileProperty = objects.fileProperty() - - @get:Internal - var javaExecutable: File - get() = javaExecutableProperty.get().asFile - set(value) { - javaExecutableProperty.set(value) - } - - /** - * A [JavaToolchainSpec] that can be passed to [JavaToolchainService] to obtain various tools (Java compiler, - * launcher, javadoc). - */ - @get:Internal - val toolchainSpec: Provider = - javaExecutableProperty.map { toolchainSpecFactory.fromJavaExecutable(it.asFile.path) } - - /** - * A [JavaLauncher] for the downloaded JBR that can be used with [JavaExec] task. - */ - @get:Internal - val javaLauncher: Provider = toolchainSpec.flatMap(javaToolchainService::launcherFor) -} diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/ToolchainSpecFactory.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/ToolchainSpecFactory.kt deleted file mode 100644 index 2b4ad89..0000000 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/downloadJBR/ToolchainSpecFactory.kt +++ /dev/null @@ -1,37 +0,0 @@ -package de.itemis.mps.gradle.downloadJBR - -import org.gradle.api.internal.provider.PropertyFactory -import org.gradle.api.model.ObjectFactory -import org.gradle.jvm.toolchain.internal.SpecificInstallationToolchainSpec -import javax.inject.Inject - -internal abstract class ToolchainSpecFactory { - @get:Inject - abstract val propertyFactory: PropertyFactory - - val method813 = try { - SpecificInstallationToolchainSpec::class.java.getMethod("fromJavaExecutable", - PropertyFactory::class.java, String::class.java) - } catch (_: NoSuchMethodException) { - null - } - - @get:Inject - abstract val objectFactory: ObjectFactory - - val method812 = try { - SpecificInstallationToolchainSpec::class.java.getMethod("fromJavaExecutable", - ObjectFactory::class.java, String::class.java) - } catch (_: NoSuchMethodException) { - null - } - - fun fromJavaExecutable(javaExecutable: String): SpecificInstallationToolchainSpec = - if (method813 != null) { - method813.invoke(null, propertyFactory, javaExecutable) as SpecificInstallationToolchainSpec - } else if (method812 != null) { - method812.invoke(null, objectFactory, javaExecutable) as SpecificInstallationToolchainSpec - } else { - throw IllegalStateException("Unsupported Gradle version, cannot create a SpecificInstallationToolchainSpec") - } -} diff --git a/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore.pm b/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore.pm deleted file mode 100644 index 66ae1ec..0000000 --- a/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore.pm +++ /dev/null @@ -1,733 +0,0 @@ -package Mac::Finder::DSStore; - -=head1 NAME - -Mac::Finder::DSStore - Read and write Macintosh Finder DS_Store files - -=head1 DESCRIPTION - -C provides a handful of functions for reading and -writing the desktop database files created by the Macintosh Finder. - -=head1 FUNCTIONS - -Many functions take a C<$store> argument which is the opened file as -an instance of L, or a C<$block> -argument which is a specific block of the file as an instance of -L. - -=cut - -use strict; -use warnings; -use POSIX qw(ceil); -use Carp qw(croak); -use Fcntl; -require Exporter; - -our($VERSION) = '1.00'; -our(@ISA) = qw(Exporter); -our(@EXPORT_OK) = qw( getDSDBEntries putDSDBEntries writeDSDBEntries makeEntries ); - -our($testpoint); - -=head2 @records = &Mac::Finder::DSStore::getDSDBEntries($store[, $callback]) - -Retrieves the "superblock" pointed to by the C entry in the store's table -of contents, and traverses the B-tree it points to, returning a list of -the records in the tree. Alternately, you can supply a callback which will -be invoked for each record, and C will return an empty list. - -=cut - -sub getBTreeRootblock { - my($store) = @_; - return $store->blockByNumber($store->{toc}->{DSDB})->read(20, 'N*'); -} - -sub getDSDBEntries { - my($file, $callback) = @_; - - my(@retval); - - $callback = sub { push(@retval, $_[0]); } unless defined $callback; - - my($rootnode, $height, $nrec, $nnodes, $blksize) = &getBTreeRootblock($file); - - my($n) = &traverse_btree($file, $rootnode, $callback); - - warn "Header node count ($nrec) not equal to actual node count ($n)" - if $n != $nrec; - - @retval; -} - -=head2 &Mac::Finder::DSStore::putDSDBEntries($store, $arrayref) - -C<$arrayref> must contain a correctly ordered list of -C objects. They will be evenly -organized into a B-tree structure and written to the C<$store>. If there is -an existing tree of records in the file already, it will be deallocated. - -This function does not flush the allocator's information back to the file. - -=cut - -sub putDSDBEntries { - my($file, $recs) = @_; - - my($tocblock, $pagesize); - my($pagecount, $reccount, $height); - - # Delete the old btree (but keep its superblock), or allocate a superblock. - if(defined($file->{toc}->{DSDB})) { - $tocblock = $file->{toc}->{DSDB}; - my($old_rootblock); - ($old_rootblock, $pagesize) = (&getBTreeRootblock($file))[0, 4]; - &freeBTreeNode($file, $old_rootblock); - } else { - $tocblock = $file->allocate( 20 ); - $file->{toc}->{DSDB} = $tocblock; - $pagesize = 0x1000; - } - - $reccount = @$recs; - $pagecount = 0; - $height = 0; - - my(@children); - - # Partition the records into btree nodes, from the bottom of - # the tree working towards the root. - do { - my(@sizes); - - if (@children) { - # Interior node: child pointers interleaved with records - @sizes = map { 4 + $_->byteSize } @$recs; - } else { - # Leaf node: just a bunch of records - @sizes = map { $_->byteSize } @$recs; - } - - # In addition to @sizes, each page contains a record - # count and a flag/childnode field (4 bytes each) - my(@interleaf) = &partition_sizes($pagesize - 8, @sizes); - my(@nchildren); - - my($next) = 0; - foreach my $non (@interleaf, 1+$#$recs) { - my($blknr) = $file->allocate($pagesize); - push(@nchildren, $blknr); - my($blk) = $file->blockByNumber($blknr, 1); - if (@children) { - &writeBTreeNode($blk, - [ @$recs[ $next .. $non-1 ] ], - [ @children[ $next .. $non ] ] ); - } else { - &writeBTreeNode($blk, - [ @$recs[ $next .. $non-1 ] ]); - } - $blk->close(1); - $next = $non + 1; - $pagecount ++; - } - - $height ++; - $recs = [ map { $recs->[$_] } @interleaf ]; - @children = @nchildren; - die unless @children == 1+@$recs; - } while(@children > 1); - die unless 0 == @$recs; - - my($masterblock) = $file->blockByNumber($tocblock, 1); - $masterblock->write('NNNNN', - $children[0], - $height - 1, - $reccount, - $pagecount, - $pagesize); - $masterblock->close; - - 1; -} - -# Given a list of sizes, break them into groups so that -# each group sums to no more than $max, not including the items -# that separate them (returned in @ejecta). -sub partition_sizes { - my($max, @sizes) = @_; - my($sum) = 0; - $sum += $_ foreach @sizes; - - return () if $sum <= $max; - - my(@ejecta); - my($bcount) = ceil($sum / $max); - my($target) = $sum / $bcount; - - my($n) = 0; - for(;;) { - my($bsum) = 0; - while( $n < @sizes && $bsum < $target && ($bsum + $sizes[$n]) < $max ) { - $bsum += $sizes[$n]; - $n ++; - } - - last if $n >= @sizes; - - push(@ejecta, $n); - $n++; - } - - @ejecta; -} - -sub traverse_btree { - my($store, $nodenr, $callback) = @_; - my($count); - my($values, $pointers) = &readBTreeNode( $store->blockByNumber( $nodenr ) ); - - if ($testpoint) { - my($o) = Mac::Finder::DSStore::BuddyAllocator::StringBlock->new(); - { - # Temporarily disable the test point so writeBTreeNode doesn't - # recursively invoke it - local($testpoint) = undef; - &writeBTreeNode($o, $values, $pointers); - } - my($actual) = $store->blockByNumber( $nodenr )->copyback; - my($roundtrip) = $o->copyback; - $actual = substr($actual, 0, length($roundtrip)); - $testpoint->( $actual, $roundtrip ); - } - - $count = @$values; - - if (defined $pointers) { - die "Value count should be one less than pointer count" - unless ( @$values + 1 ) == ( @$pointers ) ; - $count += &traverse_btree($store, shift(@$pointers), $callback); - while(@$values) { - &{$callback}(shift @$values); - $count += &traverse_btree($store, shift(@$pointers), $callback); - } - } else { - &{$callback}($_) foreach @$values; - } - - $count; -} - -sub freeBTreeNode { - my($allocator, $nodeid) = @_; - my($block) = $allocator->blockByNumber( $nodeid ); - - if($block->read(4, 'N') != 0) { - $block->seek(0); - my(undef, $pointers) = &readBTreeNode($block); - &freeBTreeNode($allocator, $_) foreach @$pointers; - } - - $allocator->free($nodeid); -} - -sub readBTreeNode { - my($node) = @_; - - my($pointer) = $node->read(4, 'N'); - - my($count) = $node->read(4, 'N'); - if ($pointer > 0) { - my(@pointers, @values); - while($count) { - push(@pointers, $node->read(4, 'N')); - push(@values, Mac::Finder::DSStore::Entry->readEntry($node)); - $count --; - } - push(@pointers, $pointer); - return \@values, \@pointers; - } else { - my(@values); - while($count) { - push(@values, Mac::Finder::DSStore::Entry->readEntry($node)); - $count --; - } - return \@values, undef; - } -} - -sub writeBTreeNode { - my($into, $values, $pointers) = @_; - - if (!$pointers) { - # A leaf node: no pointers, just database entries. - $into->write('NN', 0, scalar(@$values)); - $_->write($into) foreach @$values; - } else { - # An internal node: interleaved pointers and values, - # with the final pointer moved to the front. - my(@vals) = @$values; - my(@ps) = @$pointers; - die "number of pointers must be one more than number of entries" - unless 1+@vals == @ps; - $into->write('NN', pop(@ps), scalar(@vals)); - while(@vals) { - $into->write('N', shift(@ps)); - ( shift(@vals) )->write($into); - } - } - - if($testpoint) { - my($x) = [ &readBTreeNode($into->copyback) ]; - $testpoint->( [ $values, $pointers], $x ); - } -} - -=head2 &Mac::Finder::DSStore::writeDSDBEntries($file, @entries) - -A convenience function which sorts a list of entries and writes them -to the specified file using C, then flushes the allocator's -data structures to disk. -C<$file> may be a filename or an open file handle. -The store object is returned, but you don't need to do anything else with it. - -=cut - -sub writeDSDBEntries { - my($store, $recs); - { - my($file, @entries) = @_; - - require IO::File; - require Mac::Finder::DSStore::BuddyAllocator; - - unless(ref $file) { - my($filename) = $file; - $file = IO::File->new( $filename, Fcntl::O_RDWR | Fcntl::O_CREAT ); - croak "$filename: $!, died" unless $file; - } - - if((stat($file))[7] > 32) { - $store = Mac::Finder::DSStore::BuddyAllocator->open($file); - } else { - $store = Mac::Finder::DSStore::BuddyAllocator->new($file); - } - - $recs = [ sort { $a->cmp($b) } @entries ]; - } - - putDSDBEntries($store, $recs); - $store->writeMetaData; - - $store; -} - -=head2 &Mac::Finder::DSStore::makeEntries($filename, [ what => value ... ]) - -C encapsulates some information about the format of individual -records in the DS_Store file. It returns a list of records constructed with the -given filename and with the information specified in the rest of its args. -Most args come in pairs, a name and a value, so C kind of looks -like it takes a hash. Some names take no value and some could take several. -Some produce more than one record as a result. - -See the output of the F script for an example of how -to use this, and check the source code for a list of the formats it accepts. - -This function might change in the future. - -=cut - -sub makeEntries { - my($filename, @info) = @_; - my(@results); - - while(@info) { - my($recordType) = shift @info; - - if ($recordType =~ /^....$/) { - my($record) = Mac::Finder::DSStore::Entry->new($filename, $recordType); - $record->value( shift @info ); - push(@results, $record); - } elsif ($recordType =~ /^(....)_hex$/) { - my($record) = Mac::Finder::DSStore::Entry->new($filename, $1); - $record->value( pack('H*', shift @info) ); - push(@results, $record); - } else { - my($mkr) = $Mac::Finder::DSStore::Entry::{'make_'.$recordType}; - croak "Don't know how to handle '$recordType'" unless $mkr; - push(@results, &{$mkr}($filename, $recordType, \@info)); - } - } - - @results; -} - -package Mac::Finder::DSStore::Entry; - -=head1 Mac::Finder::DSStore::Entry - -This class holds the individual records from the database. Each record -contains a filename (in some cases, "." to refer to the containing -directory), a 4-character record type, and a value. The value is -one of a few concrete types, according to the record type. - -=cut - -use strict; -use warnings; -use Encode (); -use Carp qw(croak); - -# -# Concrete types of known ids -# -our(%types) = ( - 'BKGD' => 'blob', - 'bwsp' => 'blob', - 'cmmt' => 'ustr', - 'dilc' => 'blob', - 'dscl' => 'bool', - 'extn' => 'ustr', - 'fwi0' => 'blob', - 'fwsw' => 'long', - 'fwvh' => 'shor', - 'GRP0' => 'ustr', - 'icgo' => 'blob', - 'icsp' => 'blob', - 'icvo' => 'blob', - 'ICVO' => 'bool', - 'icvp' => 'blob', - 'icvt' => 'shor', - 'Iloc' => 'blob', - 'info' => 'blob', - 'lg1S' => 'comp', - 'logS' => 'comp', - 'lssp' => 'blob', - 'lsvo' => 'blob', - 'LSVO' => 'bool', - 'lsvP' => 'blob', - 'lsvp' => 'blob', - 'lsvt' => 'shor', - 'moDD' => 'dutc', - 'modD' => 'dutc', - 'ph1S' => 'comp', - 'phyS' => 'comp', - 'pict' => 'blob', - 'vSrn' => 'long', - 'vstl' => 'type', - ); - -=head2 $entry = ...::Entry->new($filename, $typecode) - -Creates a new entry with no value. The concrete type is inferred from the -record type code. - -=head2 $entry->filename - -Gets the filename of an entry. - -=head2 $entry->strucId - -Gets the record type of this entry, as a four-character string, indicating -what aspect of the file the entry describes. - -=head2 $entry->value([$value]) - -Gets or sets the value of an entry. - -If the concrete type is C or C, the value is interpreted as a byte string; -if it is C, as a character string. -If the concrete type is C, C, C, C, or C, -then the value should be an integer. - -=cut - -sub new { - my($class, $filename, $strucId, @opts) = @_; - - croak "no opts supported yet, died" if @opts; - - bless([ $filename, $strucId, $types{$strucId}, undef ], - ref $class || $class); -} - -sub filename { - $_[0]->[0]; -} - -sub strucId { - $_[0]->[1]; -} - -sub value { - my($self, $value) = @_; - - return $self->[3] unless defined $value; - - croak "Can't set a value on an entry with no concrete type" - unless defined($self->[2]); - - my($t) = $self->[2]; - if($t eq 'blob' or $t eq 'ustr') { - $self->[3] = '' . $value; - } elsif ($t eq 'bool' or $t eq 'shor' or $t eq 'long') { - $self->[3] = 0 + $value; - } elsif ($t eq 'type') { - $value = '' . $value; - croak "'type' values must be exactly four bytes long" - unless length($value) == 4; - $self->[3] = $value; - } else { - die "Unknown concrete type $t, died"; - } - - $self->[3]; -} - -sub readEntry { - my($class, $block) = @_; - - my($filename, $strucId, $strucType, $value); - - $filename = &readFilename($block); - $strucId = $block->read(4); - $strucType = $block->read(4); - - if ($strucType eq 'bool') { - $value = $block->read(1, 'C'); - } elsif ($strucType eq 'long' or $strucType eq 'shor') { - $value = $block->read(4, 'N'); - } elsif ($strucType eq 'blob') { - my($bloblen) = $block->read(4, 'N'); - $value = $block->read($bloblen); - } elsif ($strucType eq 'ustr') { - my($strlen) = $block->read(4, 'N'); - $value = Encode::decode('UTF-16BE', $block->read(2 * $strlen)); - } elsif ($strucType eq 'type') { - $value = $block->read(4); - } elsif ($strucType eq 'comp' || $strucType eq 'dutc') { - $value = $block->read(8, 'Q>'); - } else { - die "Unknown struc type '$strucType', died"; - } - - return bless([ $filename, $strucId, $strucType, $value ], - ref($class) || $class); -} - -sub readFilename { - my($block) = @_; - - my($flen) = $block->read(4, 'N'); - my($utf16be) = $block->read(2 * $flen); - - return Encode::decode('UTF-16BE', $utf16be, Encode::FB_CROAK); -} - -sub byteSize { - my($filename, $strucId, $strucType, $value) = @{$_[0]}; - my($size); - - # TODO: We're assuming that the filename is completely normal - # basic-multilingual-plane characters, and doesn't need to be de/re- - # composed or anything. - $size = length($filename) * 2 + 12; - # 12 bytes: 4 each for filename length, struct id, and struct type - - if ($strucType eq 'long' or $strucType eq 'shor' or $strucType eq 'type') { - $size += 4; - } elsif ($strucType eq 'bool') { - $size += 1; - } elsif ($strucType eq 'blob') { - $size += 4 + length($value); - } elsif ($strucType eq 'ustr') { - $size += 4 + 2 * length($value); - } elsif ($strucType eq 'comp' or $strucType eq 'dutc') { - $size += 8; - } else { - die "Unknown struc type '$strucType', died"; - } - - $size; -} - -sub write { - my($self, $into) = @_; - - my($fname) = Encode::encode('UTF-16BE', $self->[0]); - - my($strucType) = $self->[2]; - - $into->write('N a* a4 a4', length($fname)/2, $fname, - $self->[1], $strucType); - - if ($strucType eq 'long' or $strucType eq 'shor') { - $into->write('N', $self->[3]); - } elsif ($strucType eq 'bool') { - $into->write('C', $self->[3]); - } elsif ($strucType eq 'blob') { - $into->write('N', length($self->[3])); - $into->write($self->[3]); - } elsif ($strucType eq 'ustr') { - $into->write('N', length($self->[3])); - $into->write(Encode::encode('UTF-16BE', $self->[3])); - } elsif ($strucType eq 'type') { - $into->write('a4', $self->[3]); - } elsif ($strucType eq 'comp' or $strucType eq 'dutc') { - $into->write('Q>', $self->[3]); - } else { - die "Unknown struc type '$strucType', died"; - } -} - -=head2 $entry->cmp($other) - -Returns -1, 0, or 1 depending on the relative ordering of the two entries, -according to (a guess at) the record ordering used by the store's B-tree. - -=cut - -sub cmp { - my($self, $other) = @_; - - # - # There's probably some wacky Mac-specific Unicode collation - # rule for these, but case-insensitive comparison is a good - # approximation - # - - # Ordering in the btree is Finder-filename-ordering on the files, - # and simple bytewise ordering on the structure IDs. - - ( lc($self->[0]) cmp lc($other->[0]) ) - || - ( $self->[1] cmp $other->[1] ); -} - -# -# The make_foo subs are used by Mac::Finder::DSStore::makeEntries. -# - -sub make_BKGD_default { - my($filename, undef, undef) = @_; - - my($rec) = Mac::Finder::DSStore::Entry->new($filename, 'BKGD'); - $rec->value( pack('A4 x8', 'DefB') ); - $rec; -} - -sub make_BKGD_color { - my($filename, $strucId, $argv) = @_; - my($color) = shift @$argv; - my($rgb); - - if ($color =~ /^\#([0-9a-f]+)$/i) { - if(length($1) == 3) { - ( $rgb = $1 ) =~ s/(.)(.)(.)/$1$1$1$1$2$2$2$2$3$3$3$3/; - } elsif (length($1) == 6) { - ( $rgb = $1 ) =~ s/(..)(..)(..)/$1$1$2$2$3$3/; - } elsif (length($1) == 12) { - $rgb = $1; - } - } - - croak "Can't parse color string '$color'" - unless $rgb; - - my($rec) = Mac::Finder::DSStore::Entry->new($filename, 'BKGD'); - $rec->value( pack('A4 H12 x2', 'ClrB', $rgb) ); - - $rec; -} - -sub make_BKGD_alias { - my($filename, $strucId, $argv) = @_; - - my($image) = shift @$argv; - - if(!ref $image) { - require Mac::Memory; - require Mac::Files; - $image = Mac::Files::NewAlias($image); - } - - my($isize) = $image->size; - my($bkgd, $pict); - - $bkgd = Mac::Finder::DSStore::Entry->new($filename, 'BKGD'); - $bkgd->value( pack('A4 N nn', 'PctB', $isize, 0, 0) ); - - $pict = Mac::Finder::DSStore::Entry->new($filename, 'pict'); - $pict->value( $image->get ); - - ( $bkgd, $pict ); -} - -sub _make_packed { - my($filename, $strucId, $fmt, @values) = @_; - my($record) = Mac::Finder::DSStore::Entry->new($filename, $strucId); - $record->value( pack($fmt, @values) ); - $record; -} - -sub _make_packed_arrayref { - my($filename, $strucId, $argv, $format, $reqcount, $dflt) = @_; - my($values) = shift @$argv; - - croak "$strucId argument must be an array ref" - unless ref $values; - - croak "$strucId argument must have at least $reqcount items" - unless $reqcount <= @$values; - - my($max) = $reqcount + @$dflt; - - croak "$strucId argument can't have more than $max items" - if $max < @$values; - - my(@fields) = @$values; - if ($max > @fields) { - push(@fields, @{$dflt}[ ( @fields - $max ) .. -1 ]); - } - - return &_make_packed($filename, substr($strucId, 0, 4), - $format, @fields); -} - -sub make_Iloc_xy { - my($filename, $strucId, $argv) = @_; - return &_make_packed_arrayref($filename, $strucId, $argv, - 'NN nnnn', 2, [65535, 65535, 65535, 0]); -} - -sub make_fwi0_flds { - my($filename, $strucId, $argv) = @_; - my($flds) = shift @$argv; - - croak "$strucId argument must have 7 values" - unless 7 == @$flds; - - return &_make_packed($filename, 'fwi0', 'n4 A4 n*', @$flds); -} - - -=head1 SEE ALSO - -See L for more detailed information on -the record types found in a DS_Store file. - -See L for the low-level organization -of the DS_Store file. - -=head1 AUTHOR - -Copyright 2008 by Wim Lewis Ewiml@hhhh.orgE. - -Some information is from Mark Mentovai via the Mozilla project. -Thanks also to Martin Baker for bug reports. - -=cut - -1; diff --git a/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore/BuddyAllocator.pm b/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore/BuddyAllocator.pm deleted file mode 100644 index 7664718..0000000 --- a/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/Mac/Finder/DSStore/BuddyAllocator.pm +++ /dev/null @@ -1,783 +0,0 @@ -package Mac::Finder::DSStore::BuddyAllocator; - -=head1 NAME - -Mac::Finder::DSStore::BuddyAllocator - Allocate space within a file - -=head1 DESCRIPTION - -C -implements a buddy-allocation scheme within a file. It's used by -C to read certain files created by the Macintosh -Finder. - -The allocation methods do not perform any actual file I/O. -The contents of allocated blocks are read and written by the caller using -methods on C. -If the C and C methods are used, -or if the C hash is modified, -C must be called for the changes to be reflected in the file. - -=head1 METHODS - -=cut - -use strict; -use warnings; -use Carp; - -our($VERSION) = '1.00'; - -# Debug logging. Uncomment these and all uses of them to activate. -# It might be nice to make this more easily switchable. -#our($loglevel) = 0; -#sub logf { -# print STDERR ( ' ' x $loglevel ) . sprintf($_[0], @_[1 .. $#_ ]) . "\n"; -#} - -=head2 $allocator = Mac::Finder::DSStore::BuddyAllocator->open($fh) - -C constructs a new buddy allocator -and initializes its state from the information in the file. -The file handle is retained by the allocator for future -operations. - -=cut - -sub open { - my($class, $fh) = @_; - - binmode($fh); - - # read the file header: 32 bytes, plus a mysterious extra - # four bytes at the front - my($fheader); - $fh->read($fheader, 4 + 0x20) == 0x24 - or die "Can't read file header: $!"; - my($magic1, $magic, $offset, $size, $offset2, $unk2) = unpack('N a4 NNN a16', $fheader); - die 'bad magic' unless $magic eq 'Bud1' and $magic1 == 1; - die 'inconsistency: two root addresses are different' - unless $offset == $offset2; - - my($self) = { - fh => $fh, - unk2 => $unk2, - fudge => 4, # add this to offsets for some unknown reason - }; - bless($self, ref($class) || $class); - - # retrieve the root/index block which contains the allocator's - # book-keeping data - my ($rootblock) = $self->getBlock($offset, $size); - - # parse out the offsets of all the allocated blocks - # these are in tagged offset format (27 bits offset, 5 bits size) - my($offsetcount, $unk3) = $rootblock->read(8, 'NN'); - # not sure what the word following the offset count is - $self->{'unk3'} = $unk3; - # For some reason, offsets are always stored in blocks of 256. - my(@offsets); - while($offsetcount > 0) { - push(@offsets, $rootblock->read(1024, 'N256')); - $offsetcount -= 256; - } - # 0 indicates an empty slot; don't need to keep those around - while($offsets[$#offsets] == 0) { pop(@offsets); } - grep { $_ = undef if $_ == 0 } @offsets; - - # Next, read N key/value pairs - my($toccount) = $rootblock->read(4, 'N'); - my($toc) = { - }; - while($toccount--) { - my($len) = $rootblock->read(1, 'C'); - my($name) = $rootblock->read($len); - my($value) = $rootblock->read(4, 'N'); - $toc->{$name} = $value; - } - - $self->{'offsets'} = \@offsets; - $self->{'toc'} = $toc; - - # Finally, read the free lists. - my($freelists) = { }; - for(my $width = 0; $width < 32; $width ++) { - my($blkcount) = $rootblock->read(4, 'N'); - $freelists->{$width} = [ $rootblock->read(4 * $blkcount, 'N*') ]; - } - $self->{'freelist'} = $freelists; - - return $self; -} - -=head2 $allocator = Mac::Finder::DSStore::BuddyAllocator->new($fh) - -Similar to C, but does not read anything from the file. This -can be used to create a new file from scratch. - -=cut - -sub new { - my($cls, $fh) = @_; - - binmode($fh) if defined($fh); - - my($self) = { - fh => $fh, - toc => { }, - offsets => [ ], - freelist => { }, - - # And the mystery meat goes here... - unk2 => pack('NNNN', 0x100C, 0x0087, 0x200B, 0 ), - unk3 => 0, - fudge => 4 - }; - bless($self, ref $cls || $cls); - - # All our freelists are empty... - foreach my $width (0 .. 30) { - $self->{freelist}->{$width} = [ ]; - } - # ... except for a single 2GB block starting at 0 - $self->{freelist}->{31} = [ 0 ]; - - # Allocate the header block, 2^5 bytes wide - my($hdr) = $self->_alloc(5); - # it had better be at offset zero - ( $hdr == 0 ) or die; - - $self; -} - -=head2 $allocator->close( ) - -Closes the underlying file handle. - -=cut - -sub close { - my($self) = @_; - my($fh) = $self->{fh}; - - delete $self->{fh}; - - $fh->close; -} - -=head2 $allocator->listBlocks($verbose) - -List all the blocks in order and see if there are any gaps or overlaps. -If C<$verbose> is true, then the blocks are listed to the current -output filehandle. Returns true if the allocated and free blocks -have no gaps or overlaps. - -=cut - -sub listBlocks { - my($self, $verbose) = @_; - my(%byaddr); - my($addr, $len); - - # We store all blocks (allocated and free) in %byaddr, - # then go through its keys in order - - # Store the implicit 32-byte block that holds the file header - push(@{$byaddr{0}}, "5 (file header)"); - - # Store all the numbered/allocated blocks from @offsets - for my $blnum (0 .. $#{$self->{'offsets'}}) { - my($addr_size) = $self->{'offsets'}->[$blnum]; - next unless defined $addr_size; - $addr = $addr_size & ~0x1F; - $len = $addr_size & 0x1F; - push(@{$byaddr{$addr}}, "$len (blkid $blnum)"); - } - - # Store all the blocks in the freelist(s) - for $len (keys %{$self->{'freelist'}}) { - for $addr (@{$self->{'freelist'}->{$len}}) { - push(@{$byaddr{$addr}}, "$len (free)"); - } - } - - my($gaps, $overlaps) = (0, 0); - - # Loop through the blocks in order of address - my(@addrs) = sort {$a <=> $b} keys %byaddr; - $addr = 0; - while(@addrs) { - my($next) = shift @addrs; - if ($next > $addr) { - print "... ", ($next - $addr), " bytes unaccounted for\n" - if $verbose; - $gaps ++; - } - my(@uses) = @{$byaddr{$next}}; - printf "%08x %s\n", $next, join(', ', @uses) - if $verbose; - $overlaps ++ if @uses > 1; - - # strip off the length (log_2(length) really) from the info str - ($len = $uses[0]) =~ s/ .*//; - $addr = $next + ( 1 << (0 + $len) ); - } - - ( $gaps == 0 && $overlaps == 0 ); -} - -=head2 $allocator->writeMetaData( ) - -Writes the allocator's metadata (header block and root block) -back to the file. - -=cut - -sub writeMetaData { - my($self) = @_; - - # Root block nr is hardcoded to 0. - # We don't actually care, but the DSStore btree does. - my($blocknr) = 0; - - # Before computing the size of the rootblock to allocate it, - # make sure it'll be large enough to hold its own (eventual) - # allocation information. - $self->{offsets}->[0] = undef unless exists $self->{offsets}->[0]; - - my($rbs) = $self->rootBlockSize(); - $self->allocate($rbs, $blocknr); - - $self->writeRootblock($self->blockByNumber($blocknr, 1)); - - my($blockOffset, $blockLength) = $self->blockOffset($blocknr); - - $self->{fh}->seek(0, 0); - $self->{fh}->write(pack('N', 1)); # magic1 - $self->_sought(0)->write(pack('a4 NNN a16', - 'Bud1', # magic - $blockOffset, $blockLength, $blockOffset, - $self->{unk2})); - - $self->{fh}->flush; -} - -sub rootBlockSize { - my($self) = @_; - my($size); - - $size = 8; # The offset count and the unknown field that follows it - - # The offset blocks, rounded up to a multiple of 256 entries - my($offsetcount) = scalar( @{$self->{'offsets'}} ); - my($tail) = $offsetcount % 256; - $offsetcount += 256 - $tail if ($tail); - $size += 4 * $offsetcount; - - # The table of contents - $size += 4; # count - $size += (5 + length($_)) foreach keys %{$self->{'toc'}}; - - # The freelists - foreach my $width (0 .. 31) { - $size += 4 + 4 * scalar( @{$self->{'freelist'}->{$width}} ); - } - - $size; -} - -sub writeRootblock { - my($self, $into) = @_; - - my(@offsets) = @{$self->{'offsets'}}; - - # Write the offset count & the unknown field that follows it - $into->write('NN', scalar(@offsets), $self->{'unk3'}); - - # Write the offsets (using 0 to indicate an unused slot) - $into->write('N*', map { (defined($_) && $_ > 0)? $_ : 0 } @offsets); - - # The offsets are always written in blocks of 256. - my($offsetcount) = scalar(@offsets) % 256; - if ($offsetcount > 0) { - # Fill out the last block - $into->write('N*', (0) x (256-$offsetcount)); - } - - # The DS_Store files only ever have one item in their - # table of contents, so I'm not sure if it needs to be sorted or what - my(@tockeys) = sort keys %{$self->{'toc'}}; - $into->write('N', scalar(@tockeys)); - foreach my $entry (@tockeys) { - $into->write('C a* N', length($entry), $entry, $self->{'toc'}->{$entry}); - } - - # And finally the freelists - for my $width ( 0 .. 31 ) { - my($blks) = $self->{'freelist'}->{$width}; - $into->write('N N*', scalar(@$blks), @$blks); - } -} - -=head2 $block = $allocator->blockByNumber(blocknumber[, write]) - -Retrieves a block by its block number (I block ID). - -If C is supplied and is true, then the returned block implements the -C method but not the C method. - -=head2 $block = $allocator->getBlock(offset, size) - -Retrieves a block (a BuddyAllocator::Block instance) by offset & length. -Normally you should use C instead of this method. - -=cut - -sub getBlock { - my($self, $offset, $size) = @_; - - return Mac::Finder::DSStore::BuddyAllocator::Block->new($self, $offset, $size); -} - -# Retrieve a block by its block number (small integer) -sub blockByNumber { - my($self, $id, $write) = @_; - my($addr) = $self->{offsets}->[$id]; - return undef unless $addr; - my($offset, $len); - $offset = $addr & ~0x1F; - $len = 1 << ( $addr & 0x1F ); -# print " node id $id is $len bytes at 0x".sprintf('%x', $offset)."\n"; - if (!defined($write) || !$write) { - return Mac::Finder::DSStore::BuddyAllocator::Block->new($self, $offset, $len); - } else { - return Mac::Finder::DSStore::BuddyAllocator::WriteBlock->new($self, $offset, $len); - } -} - -=head2 ( $offset, $size ) = $allocator->blockOffset(blockid) - -Retrieves the file offset and size in bytes of a given block. -The offset doesn't include the 4-byte fudge. -In scalar context, just returns the offset. - -=cut - -sub blockOffset { - my($self, $id) = @_; - my($addr) = $self->{offsets}->[$id]; - croak "Block $id is not allocated" unless $addr; - my($offset) = $addr & ~0x1F; - return $offset unless wantarray; - return ( $offset, 1 << ( $addr & 0x1F ) ); -} - -# Return freelist + index of a block's buddy in its freelist (or empty list) -sub _buddy { - my($self, $offset, $width) = @_; - my($freelist, $buddyaddr); - - $freelist = $self->{'freelist'}->{$width}; - $buddyaddr = $offset ^ ( 1 << $width ); - - return ($freelist, - grep { $freelist->[$_] == $buddyaddr } 0 .. $#$freelist ); -} - -# Free a block, coalescing ith buddies as needed. -sub _free { - my($self, $offset, $width) = @_; - - my($freelist, $buddyindex) = $self->_buddy($offset, $width); - - if(defined($buddyindex)) { - # our buddy is free. Coalesce, and add the coalesced block to flist. - my($buddyoffset) = splice(@$freelist, $buddyindex, 1); - #&logf("Combining %x with buddy %x", $offset, $buddyoffset); - $self->_free($offset & $buddyoffset, $width+1); - } else { - #&logf("Adding block %x to freelist %d", $offset, $width); - @$freelist = sort( @$freelist, $offset ); - } -} - -# Allocate a block of a specified width, splitting as needed. -sub _alloc { - my($self, $width) = @_; - - #&logf("Allocating a block of width %d", $width); - #$loglevel ++; - - my($flist) = $self->{'freelist'}->{$width}; - if (@$flist) { - # There is a block of the desired size; return it. - #&logf("Pulling %x from freelist", $flist->[0]); $loglevel --; - return shift @$flist; - } else { - # Allocate a block of the next larger size; split it. - my($offset) = $self->_alloc($width + 1); - # and put the other half on the free list. - my($buddy) = $offset ^ ( 1 << $width ); - #&logf("Splitting %x into %x and %x", $offset, $offset, $buddy); - #$loglevel ++; - $self->_free($buddy, $width); - #$loglevel -= 2; - return $offset; - } -} - -=head2 $blocknumber = $allocator->allocate($size, [$blocknumber]) - -Allocates or re-allocates a block to be at least C<$size> bytes long. -If C<$blocknumber> is given, the specified block will be grown or -shrunk if needed, otherwise a new block number will be chosen and -given to the allocated block. - -Unlike the libc C function, this may move a block even if the -block is not grown. - -=head2 $allocator->free($blocknumer) - -Releases the block number and the block associated with it back to the -block pool. - -=cut - -sub allocate { - my($self, $bytes, $blocknum) = @_; - my($offsets) = $self->{'offsets'}; - - #if(defined($blocknum)) { - # &logf("(Re)allocating %d bytes for blkid %d", $bytes, $blocknum); - #} - - if(!defined($blocknum)) { - $blocknum = 1; - # search for an empty slot, or extend the array - $blocknum++ while defined($offsets->[$blocknum]); - #&logf("Allocating %d bytes, assigning blkid %d", $bytes, $blocknum); - } - - #$loglevel ++; - - my($wantwidth) = 5; - # Minimum width, since that's how many low-order bits we steal for the tag - $wantwidth ++ while $bytes > 1 << $wantwidth; - - my($blkaddr, $blkwidth, $blkoffset); - - if(exists($offsets->[$blocknum]) && $offsets->[$blocknum]) { - $blkaddr = $offsets->[$blocknum]; - $blkwidth = $blkaddr & 0x1F; - $blkoffset = $blkaddr & ~0x1F; - if ($blkwidth == $wantwidth) { - #&logf("Block is already width %d, no change", $wantwidth); - #$loglevel --; - # The block is currently of the desired size. Leave it alone. - return $blocknum; - } else { - #&logf("Freeing wrong-sized block"); - #$loglevel ++; - # Free the current block, allocate a new one. - $self->_free($blkoffset, $blkwidth); - delete $offsets->[$blocknum]; - #$loglevel --; - } - } - - # Allocate a block, update the offsets table, and return the new offset - $blkoffset = $self->_alloc($wantwidth); - $blkaddr = $blkoffset | $wantwidth; - $offsets->[$blocknum] = $blkaddr; - #$loglevel --; - $blocknum; -} - -sub free { - my($self, $blknum) = @_; - my($blkaddr) = $self->{'offsets'}->[$blknum]; - - #&logf("Freeing block index %d", $blknum); - #$loglevel ++; - - if($blkaddr) { - my($blkoffset, $blkwidth); - $blkwidth = $blkaddr & 0x1F; - $blkoffset = $blkaddr & ~0x1F; - $self->_free($blkoffset, $blkwidth); - } - - delete $self->{'offsets'}->[$blknum]; - #$loglevel --; - undef; -} - -=head1 ATTRIBUTES - -=head2 $allocator->{toc} - -C holds a hashref whose keys are short strings and whose values -are integers. This table of contents is read and written as part of the -allocator's metadata but is not otherwise used by the allocator; -users of the allocator use it to find their data within the file. - -=head2 $allocator->{fh} - -The file handle passed in to C or C. If you find yourself needing -to use this, you should probably try to extend the class so that you don't. - -=cut - -# Used by ...::Block to get a positioned file handle. -sub _sought { - my($self, $offset) = @_; - - my($fh) = $self->{fh}; - $fh->seek($offset + $self->{fudge}, 0) - or croak; - $fh; -} - -package Mac::Finder::DSStore::BuddyAllocator::Block; - -=head1 BuddyAllocator::Block - -C instances are returned by the -C and C methods. They hold a pointer into -the file and provide a handful of useful methods. - -(There are also two other classes, C and C, -which might be returned instead. Think of this as an interface rather -than as a concrete class.) - -=head2 $block->read(length, [format]) - -Reads C bytes from the block (advancing the read pointer -correspondingly). If C is specified, the bytes read are -unpacked using the format; otherwise a byte string is returned. - -=head2 $block->length( ) - -Returns the length (or size) of this block. - -=head2 $block->seek(position[, whence]) - -Adjusts the read/write pointer within the block. - -=head2 $block->write(bytes) - -=head2 $block->write(format, items...) - -Writes data to the underlying file, at the position represented by this -block. If multiple arguments are given, the first is a format string -and the rest are the remaining arguments to C. - -=head2 $block->close([ zerofill ]) - -This is generally a no-op, but if called on a writable block with -C, then zeroes will be written from the current -location to the end of the allocated block. - -=head2 $block->copyback( ) - -Returns the block's contents as a string. For write blocks, this -reads from the file. This is just here for debugging purposes and -might change. - -=cut - -use strict; -use warnings; -use Carp; - -# -# Block objects are created by the buddy allocator; they're a -# reference to an array with the following components: -# -# [ $allocator, $value, $position] -# - -sub new { - my($class, $allocator, $offset, $size) = @_; - - my($value); - $allocator->_sought($offset)->read($value, $size) - > 0 or die; - # Previously, this died if we couldn't read the full block. - # Not sure if it's really an error not to read the full - # block if the next layer up doesn't need the full block. - # So now we're succeeding as long as we get something; if - # the reader overruns it'll die in substr(). - - bless([ $allocator, $value, 0 ], ref $class || $class); -} - -sub read { - my($self, $len, $unpack) = @_; - - my($pos) = $self->[2]; - die "out of range: pos=$pos len=$len max=".(length($self->[1])) if $pos + $len > length($self->[1]); - my($bytes) = substr($self->[1], $pos, $len); - $self->[2] = $pos + $len; - - $unpack? unpack($unpack, $bytes) : $bytes; -} - -sub length { - return CORE::length($_[0]->[1]); -} - -sub close { - 1; -} - -sub seek { - my($self, $pos, $whence) = @_; - $whence = 0 unless defined $whence; - if ($whence == 0) { - # pos = pos - } elsif ($whence == 1) { - $pos += $self->[2]; - } elsif ($whence == 2) { - $pos += $self->length(); - } else { - croak "seek: whence=$whence"; - } - $self->[2] = $pos; -} - -sub copyback { - return $_[0]->[1]; -} - -package Mac::Finder::DSStore::BuddyAllocator::WriteBlock; - -use strict; -use warnings; -use Carp; - -# -# Write blocks -# - -sub new { - my($class, $allocator, $offset, $size) = @_; - - croak "Missing arguments" - unless defined($offset) && defined($size); - croak "Bad offset" - if $offset <= 0; - - bless([ $allocator, undef, 0, $offset, $size ], ref $class || $class); -} - -sub read { - my($self) = @_; - - croak "This is a write-only block"; -} - -sub length { - return ($_[0]->[4]); -} - -sub seek { - my($self, $pos, $whence) = @_; - if ($whence == 0) { - $self->[2] = $pos; - } elsif ($whence == 1) { - $self->[2] += $pos; - } elsif ($whence == 2) { - $self->[2] = $self->length + $pos; - } else { - croak "seek: whence=$whence"; - } - undef $self->[1]; - $self; -} - -sub write { - my($self, $what, @args) = @_;; - - if (!defined($self->[1])) { - $self->[1] = $self->[0]->_sought($self->[2] + $self->[3]); - } - - if (@args) { - $what = pack($what, @args); - } - - my($wlen) = CORE::length($what); - - croak "Writing past end of block (writing $wlen at ".($self->[2]).", end is at ".($self->[4])."), died" - if $self->[2]+$wlen > $self->[4]; - - $self->[1]->write($what); - $self->[2] += $wlen; -} - -sub close { - my($self, $fill) = @_; - if (defined($fill) && $fill && $self->[2] < $self->[4]) { - $self->write("\0" x ($self->[4] - $self->[2])); - } - undef $self->[1]; - 1; -} - -# -# This is just here for debugging/testing purposes -# - -sub copyback { - my($self) = @_; - - my($r) = Mac::Finder::DSStore::BuddyAllocator::Block->new(@{$self}[0, 3, 2]); - - undef $self->[1]; # probably need to re-seek now - - return $r; -} - -package Mac::Finder::DSStore::BuddyAllocator::StringBlock; - -use strict; -use warnings; - -# -# This one's kind of handy, really, but is only used for debugging and -# test harnesses right now. -# - -sub new { - my($x) = ''; - bless(\$x, ref $_[0] || $_[0]); -} - -sub write { - my($self, $what, @args) = @_;; - - if (@args) { - $what = pack($what, @args); - } - - ${$self} .= $what; -} - -sub copyback { - ${$_[0]}; -} - -=head1 AUTHOR - -Written by Wim Lewis as part of the Mac::Finder::DSStore package. - -This file is copyright 2008 by Wim Lewis. -All rights reserved. -This program is free software; you can redistribute it and/or -modify it under the same terms as Perl itself. - - -=cut - -1; diff --git a/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/bundle_macos_jdk.sh b/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/bundle_macos_jdk.sh deleted file mode 100755 index cf5c247..0000000 --- a/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/bundle_macos_jdk.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -if [[ $# -ne 5 ]]; then - cat < *.jnilib if any .jnilib files are present - (this used to be the case for earlier versions of MPS) -3. If JDK_FILE is given, extracts JDK_FILE under Contents/$JDK_DIRNAME/ -4. Sets executable permissions on Contents/MacOS/* and appropriate Contents/bin/ files -5. Compresses the result into OUT_FILE (tar/gzip) - -IMPORTANT: All arguments must use absolute paths because the script changes the current directory several times! -EOF - exit 1 -fi - -set -o errexit # Exit immediately on any error - -# Arguments -RCP_FILE="$1" -TMP_DIR="$2" -JDK_DIRNAME="$3" -JDK_FILE="$4" -OUT_FILE="$5" - -echo "Unzipping $RCP_FILE to $TMP_DIR..." -unzip -q -o "$RCP_FILE" -d "$TMP_DIR" -BUILD_NAME=$(ls "$TMP_DIR") -CONTENTS="$TMP_DIR/$BUILD_NAME/Contents" - -if ls "$CONTENTS/bin"/*.jnilib >& /dev/null; then - echo 'Creating symlinks from *.jnilib to *.dylib:' - for f in "$CONTENTS/bin"/*.jnilib; do - b="$(basename "$f" .jnilib)" - echo " $f -> $b.dylib" - ln -sf "$b.jnilib" "$(dirname "$f")/$b.dylib" - done - echo 'Done creating symlinks' -fi - -if [[ -n "$JDK_FILE" ]]; then - if [[ ! -f "$JDK_FILE" ]]; then - echo "$JDK_FILE is not a file" - exit 1 - fi - echo "Modifying Info.plist" - sed -i -e 's/1.6\*/1.6\+/' "$CONTENTS/Info.plist" - sed -i -e 's/NoJavaDistribution/custom-jdk-bundled/' "$CONTENTS/Info.plist" - - # TODO This command appears to be useless, it only inserts a blank line into the file. - sed -i -e '/public.app-category.developer-tools/G' "$CONTENTS/Info.plist" - - sed -i -e '/public.app-category.developer-tools/a\'$'\n''NSSupportsAutomaticGraphicsSwitching' "$CONTENTS/Info.plist" - - # sed -i -e seems to work with both GNU sed and OS X sed, with the latter leaving the original file with -e suffix - # as a backup. - rm -f "$CONTENTS/Info.plist-e" - echo "Info.plist has been modified" - - echo "Extracting JDK: $JDK_FILE to $CONTENTS/$JDK_DIRNAME" - mkdir -p "$CONTENTS/$JDK_DIRNAME" - pushd "$CONTENTS/$JDK_DIRNAME" - COPY_EXTENDED_ATTRIBUTES_DISABLE=true COPYFILE_DISABLE=true tar xvf "$JDK_FILE" --exclude='._jdk' || exit 1 - echo "JDK has been extracted" - popd -fi - -chmod a+x "$CONTENTS"/MacOS/* -if ls "$CONTENTS"/bin/*.py 1> /dev/null 2>&1; then - chmod a+x "$CONTENTS"/bin/*.py -fi -chmod a+x "$CONTENTS"/bin/fs* -chmod a+x "$CONTENTS"/bin/restarter - -cd "$TMP_DIR" -COPY_EXTENDED_ATTRIBUTES_DISABLE=true COPYFILE_DISABLE=true tar czvf "$OUT_FILE" "$BUILD_NAME" -echo "Bundle created in $OUT_FILE" diff --git a/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpsdmg.pl b/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpsdmg.pl deleted file mode 100644 index ec4ac55..0000000 --- a/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpsdmg.pl +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/perl -w - -use Mac::Finder::DSStore qw( writeDSDBEntries makeEntries ); -use Mac::Memory qw( ); -use Mac::Files qw( NewAliasMinimal ); - -$volumeName = $ARGV[0]; -$name = $ARGV[1]; -$bg_pic = $ARGV[2]; - -&writeDSDBEntries("/Volumes/$volumeName/.DS_Store", - &makeEntries(".background", Iloc_xy => [ 560, 170 ]), - &makeEntries(".DS_Store", Iloc_xy => [ 610, 170 ]), - &makeEntries(".fseventsd", Iloc_xy => [ 660, 170 ]), - &makeEntries(".Trashes", Iloc_xy => [ 710, 170 ]), - &makeEntries(" ", Iloc_xy => [ 335, 120 ]), - &makeEntries(".", - BKGD_alias => NewAliasMinimal("/Volumes/$volumeName/.background/$bg_pic"), - ICVO => 1, - fwi0_flds => [ 100, 400, 396, 855, "icnv", 0, 0 ], - fwsw => 170, - fwvh => 296, - icvo => pack('A4 n A4 A4 n*', "icv4", 100, "none", "botm", 0, 0, 0, 0, 0, 1, 0, 100, 1), - icvt => 12 - ), - &makeEntries("$name.app", Iloc_xy => [ 110, 120 ]) -); - diff --git a/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpsdmg.sh b/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpsdmg.sh deleted file mode 100755 index 12787aa..0000000 --- a/mps-gradle-plugin/src/main/resources/de/itemis/mps/gradle/mpsdmg.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash -if [[ $# -ne 3 ]]; then - cat < -o [-j ] [-p -k -i ]" >&2 - exit 1;; - :) echo "option: -$OPTARG requires an argument" >&2 - exit 1;; - esac -done -shift $((OPTIND -1)) #remove options that have already been handled from $@ - -if [[ -z "$RCP_FILE" || -z "$OUTPUT_DIR" ]]; then - echo "$USAGE" - exit 1 -fi - -echo "Unzipping $RCP_FILE to $OUTPUT_DIR..." -unzip -q -o "$RCP_FILE" -d "$OUTPUT_DIR" -BUILD_NAME=$(ls "$OUTPUT_DIR") -CONTENTS="$OUTPUT_DIR/$BUILD_NAME/Contents" - -if ls "$CONTENTS/bin"/*.jnilib >& /dev/null; then - echo 'Creating symlinks from *.jnilib to *.dylib:' - for f in "$CONTENTS/bin"/*.jnilib; do - b="$(basename "$f" .jnilib)" - echo " $f -> $b.dylib" - ln -sf "$b.jnilib" "$(dirname "$f")/$b.dylib" - done - echo 'Done creating symlinks' -fi - -if [[ -n "$JDK_FILE" ]]; then - if [[ ! -f "$JDK_FILE" ]]; then - echo "$JDK_FILE is not a file" - exit 1 - fi - echo "Modifying Info.plist" - sed -i -e 's/1.6\*/1.6\+/' "$CONTENTS/Info.plist" - sed -i -e 's/NoJavaDistribution/custom-jdk-bundled/' "$CONTENTS/Info.plist" - - # TODO This command appears to be useless, it only inserts a blank line into the file. - sed -i -e '/public.app-category.developer-tools/G' "$CONTENTS/Info.plist" - - sed -i -e '/public.app-category.developer-tools/a\'$'\n''NSSupportsAutomaticGraphicsSwitching' "$CONTENTS/Info.plist" - - # sed -i -e seems to work with both GNU sed and OS X sed, with the latter leaving the original file with -e suffix - # as a backup. - rm -f "$CONTENTS/Info.plist-e" - echo "Info.plist has been modified" - - echo "Extracting JDK: $JDK_FILE to $CONTENTS/jre" - mkdir -p "$CONTENTS/jre" - pushd "$CONTENTS/jre" - COPY_EXTENDED_ATTRIBUTES_DISABLE=true COPYFILE_DISABLE=true tar xvf "$JDK_FILE" --exclude='._jdk' || exit 1 - echo "JDK has been extracted" - popd -fi - -HELP_FILE=$(ls "$CONTENTS/Resources/" | grep -i help) || HELP_FILE='' -HELP_DIR="$CONTENTS/Resources/$HELP_FILE/Contents/Resources/English.lproj/" - -if [[ -d "$HELP_DIR" ]]; then - echo "Building help indices for $HELP_DIR" - hiutil -Cagvf "$HELP_DIR/search.helpindex" "$HELP_DIR" -fi - -# Make sure your certificate is imported into local KeyChain -if [[ -n "$SIGN_PW" && -n "$SIGN_KEY_CHAIN" && -n "$SIGN_IDENTITY" ]]; then - echo "Signing application $BUILD_NAME" - echo "key chain: $SIGN_KEY_CHAIN" - echo "sign identity: $SIGN_IDENTITY" - security unlock-keychain -p $SIGN_PW $SIGN_KEY_CHAIN - codesign -v --deep -s "$SIGN_IDENTITY" "$OUTPUT_DIR/$BUILD_NAME" - echo "signing is done" - echo "check sign" - codesign -v "$OUTPUT_DIR/$BUILD_NAME" -vvvvv - echo "check sign done" -else - echo "for signing the application $BUILD_NAME: SIGN_PW, SIGN_KEY_CHAIN and SIGN_IDENTITY needs to be provided" -fi - -chmod a+x "$CONTENTS"/MacOS/* -chmod a+x "$CONTENTS"/bin/*.py -chmod a+x "$CONTENTS"/bin/fs* -chmod a+x "$CONTENTS"/bin/restarter \ No newline at end of file From 3af6615c9aa9705f73fad62cf66b2cd689a9645d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 18:00:00 +0200 Subject: [PATCH 27/44] Remove GetMpsInBrowser The task only opened the JetBrains download page in a browser and did not pull its weight. Co-Authored-By: Claude Opus 4.7 (1M context) --- mps-gradle-plugin/CHANGELOG.md | 2 + mps-gradle-plugin/api/mps-gradle-plugin.api | 11 ---- .../itemis/mps/gradle/GetMpsInBrowser.groovy | 54 ------------------- 3 files changed, 2 insertions(+), 65 deletions(-) delete mode 100644 mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/GetMpsInBrowser.groovy diff --git a/mps-gradle-plugin/CHANGELOG.md b/mps-gradle-plugin/CHANGELOG.md index c7f322e..79e635d 100644 --- a/mps-gradle-plugin/CHANGELOG.md +++ b/mps-gradle-plugin/CHANGELOG.md @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `DownloadJbrForPlatform` task and the `downloadJBR` package have been removed. Use the [jbr-toolchain plugin](https://github.com/specificlanguages/mps-gradle-plugin/tree/master/subprojects/jbr-toolchain) if JetBrains Runtime is required. +- `GetMpsInBrowser` task has been removed. It only opened the JetBrains download page in a browser and did not pull its + weight. ### Added diff --git a/mps-gradle-plugin/api/mps-gradle-plugin.api b/mps-gradle-plugin/api/mps-gradle-plugin.api index 003b1ac..38a68a2 100644 --- a/mps-gradle-plugin/api/mps-gradle-plugin.api +++ b/mps-gradle-plugin/api/mps-gradle-plugin.api @@ -34,17 +34,6 @@ public class de/itemis/mps/gradle/GenerateLibrariesXml : org/gradle/api/DefaultT public fun setOverrides (Ljava/lang/Object;)V } -public class de/itemis/mps/gradle/GetMpsInBrowser : org/gradle/api/DefaultTask, groovy/lang/GroovyObject { - public static synthetic field __$stMC Z - protected synthetic fun $getStaticMetaClass ()Lgroovy/lang/MetaClass; - public fun ()V - public fun build ()Ljava/lang/Object; - public fun getMetaClass ()Lgroovy/lang/MetaClass; - public fun getVersion ()Ljava/lang/String; - public fun setMetaClass (Lgroovy/lang/MetaClass;)V - public fun setVersion (Ljava/lang/String;)Ljava/lang/Object; -} - public class de/itemis/mps/gradle/Pom : groovy/lang/GroovyObject { public static synthetic field __$stMC Z protected synthetic fun $getStaticMetaClass ()Lgroovy/lang/MetaClass; diff --git a/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/GetMpsInBrowser.groovy b/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/GetMpsInBrowser.groovy deleted file mode 100644 index 252f91b..0000000 --- a/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/GetMpsInBrowser.groovy +++ /dev/null @@ -1,54 +0,0 @@ -package de.itemis.mps.gradle - -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.TaskAction -import org.apache.tools.ant.taskdefs.condition.Os - -import java.awt.Desktop - -class GetMpsInBrowser extends DefaultTask { - - @Input - String version - - def setVersion(String version) { - this.version = version - } - - private String getMajorPart() { - def split = version.split("\\.") - if (split.length == 2) { - return version - } - - return split.take(2).join(".") - } - - private URI getDownloadUrl() { - def major = getMajorPart() - - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - return new URI("https://download.jetbrains.com/mps/${major}/MPS-${version}.exe") - } else if (Os.isFamily(Os.FAMILY_MAC)) { - return new URI("https://download.jetbrains.com/mps/${major}/MPS-${version}-macos-jdk-bundled.dmg") - } else if (Os.isFamily(Os.FAMILY_UNIX)) { - return new URI("https://download.jetbrains.com/mps/${major}/MPS-${version}.tar.gz") - } else { - print "Warning: could not determine OS downloading generic distribution" - return new URI("http://download.jetbrains.com/mps/${major}/MPS-${version}.zip") - } - - } - - @TaskAction - def build() { - - if (Desktop.isDesktopSupported()) { - Desktop.getDesktop().browse(getDownloadUrl()) - } else { - throw new GradleException("this task is not supported in headless mode") - } - } -} From 7dd411096592d3caf1e301f4008100da81f85380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 18:04:48 +0200 Subject: [PATCH 28/44] Upgrade to Gradle 9.4.1 and simplify Kotlin setup Gradle 9 enforces plugin validation rules as errors: every task type must declare cacheability and all @InputFile[s] properties must carry a normalization strategy. Applies @DisableCachingByDefault to the Ant runners and XML generator, and @PathSensitive to their file inputs. JavaExec became abstract in Gradle 9, so Remigrate is converted to an abstract class whose properties Gradle instantiates automatically, following the same pattern as MpsExecute. The @Inject constructor and manual objectFactory.property() initialization are dropped; conventions move into an init block. Since Gradle 9 mandates JDK 17, consumers must also use 17; the explicit kotlin("jvm") plugin and kotlin-stdlib dependency are dropped (kotlin-dsl provides both), the apiVersion = 1.7 pin is dropped, and targetCompatibility moves to 17 across both subbuilds. The Java 11 leg is removed from the CI matrix (still downloaded as a side-install to run MPS 2021.x-based tests). Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/gradle.yml | 2 +- gradle/libs.versions.toml | 6 -- gradle/wrapper/gradle-wrapper.properties | 4 +- mps-gradle-plugin-api/build.gradle.kts | 7 +-- mps-gradle-plugin-api/gradle.lockfile | 50 +++++++++------- mps-gradle-plugin/api/mps-gradle-plugin.api | 25 ++++---- mps-gradle-plugin/build.gradle.kts | 9 +-- mps-gradle-plugin/gradle.lockfile | 60 ++++++++++--------- .../mps/gradle/GenerateLibrariesXml.groovy | 6 +- .../de/itemis/mps/gradle/RunAntScript.kt | 8 ++- .../de/itemis/mps/gradle/tasks/MpsMigrate.kt | 1 + .../de/itemis/mps/gradle/tasks/Remigrate.kt | 40 +++++-------- 12 files changed, 106 insertions(+), 112 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index a3ba9a8..1bbd386 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -25,7 +25,7 @@ jobs: contents: read strategy: matrix: - java: [ 11, 17, 21 ] + java: [ 17, 21 ] steps: - uses: actions/checkout@v4 # Java 11 is always needed to run the tests because they use MPS 2021.x diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2ed1c4a..30198e1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,9 +1,4 @@ [versions] -#versions -kotlinApi = "1.7" -kotlin = "1.7.10" -kotlinJvmTarget = "11" - # plugins kotlinCompatibilityValidator = "0.18.1" @@ -17,7 +12,6 @@ launcher = "2.8.0.+" kotlin-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "kotlinCompatibilityValidator" } [libraries] -kotlin-stdlib = {group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin"} swiftzer-semver = {group = "net.swiftzer.semver", name="semver", version.ref="semver"} junit = {group = "junit", name="junit", version.ref="junit"} itemis-gradle-git-based-versioning = {group= "de.itemis.mps.gradle", name = "git-based-versioning", version.ref="gitBasedVersioning"} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 78cb6e1..8e61ef1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=bd71102213493060956ec229d946beee57158dbd89d0e62b91bca0fa2c5f3531 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip +distributionSha256Sum=2ab2958f2a1e51120c326cad6f385153bb11ee93b3c216c5fccebfdfbb7ec6cb +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/mps-gradle-plugin-api/build.gradle.kts b/mps-gradle-plugin-api/build.gradle.kts index 9eb5eb1..38d278b 100644 --- a/mps-gradle-plugin-api/build.gradle.kts +++ b/mps-gradle-plugin-api/build.gradle.kts @@ -1,6 +1,3 @@ -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.dsl.KotlinVersion - plugins { `kotlin-dsl` `maven-publish` @@ -73,14 +70,12 @@ publishing { } java { - targetCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_17 withSourcesJar() } kotlin { compilerOptions { - jvmTarget = JvmTarget.fromTarget(libs.versions.kotlinJvmTarget.get()) - apiVersion = KotlinVersion.fromVersion(libs.versions.kotlinApi.get()) allWarningsAsErrors = true } } diff --git a/mps-gradle-plugin-api/gradle.lockfile b/mps-gradle-plugin-api/gradle.lockfile index 87cf800..308b86c 100644 --- a/mps-gradle-plugin-api/gradle.lockfile +++ b/mps-gradle-plugin-api/gradle.lockfile @@ -1,29 +1,35 @@ # This is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. -org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-assignment-compiler-plugin-embeddable:2.0.21=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest -org.jetbrains.kotlin:kotlin-build-common:2.0.21=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-build-tools-api:2.0.21=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-build-tools-impl:2.0.21=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-compiler-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-compiler-runner:2.0.21=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-daemon-client:2.0.21=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-daemon-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:2.0.21=kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-metadata-jvm:2.0.21=bcv-rt-jvm-cp-resolver +io.github.java-diff-utils:java-diff-utils:4.12=kotlinInternalAbiValidation +org.jetbrains.kotlin:abi-tools-api:2.3.0=kotlinInternalAbiValidation +org.jetbrains.kotlin:abi-tools:2.3.0=kotlinInternalAbiValidation +org.jetbrains.kotlin:kotlin-assignment-compiler-plugin-embeddable:2.3.0=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-build-tools-api:2.3.0=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-build-tools-compat:2.3.0=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-build-tools-impl:2.3.0=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-compiler-embeddable:2.3.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-compiler-runner:2.3.0=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-daemon-client:2.3.0=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-daemon-embeddable:2.3.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-klib-abi-reader:2.3.0=kotlinInternalAbiValidation +org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:2.3.0=kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-metadata-jvm:2.3.0=bcv-rt-jvm-cp-resolver,kotlinInternalAbiValidation org.jetbrains.kotlin:kotlin-native-prebuilt:2.0.21=kotlinNativeBundleConfiguration org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-reflect:2.0.21=compileClasspath,compileOnlyDependenciesMetadata,embeddedKotlin,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath -org.jetbrains.kotlin:kotlin-sam-with-receiver-compiler-plugin-embeddable:2.0.21=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest -org.jetbrains.kotlin:kotlin-script-runtime:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-scripting-common:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest -org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest -org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest -org.jetbrains.kotlin:kotlin-scripting-jvm:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest -org.jetbrains.kotlin:kotlin-stdlib:2.0.21=bcv-rt-jvm-cp-resolver,compileClasspath,compileOnlyDependenciesMetadata,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains:annotations:13.0=bcv-rt-jvm-cp-resolver,compileClasspath,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-reflect:2.0.21=compileOnlyDependenciesMetadata +org.jetbrains.kotlin:kotlin-reflect:2.3.0=compileClasspath,embeddedKotlin,testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-sam-with-receiver-compiler-plugin-embeddable:2.3.0=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-script-runtime:2.3.0=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-scripting-common:2.3.0=compilePluginsBlocksPluginClasspathElements,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:2.3.0=compilePluginsBlocksPluginClasspathElements,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:2.3.0=compilePluginsBlocksPluginClasspathElements,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-scripting-jvm:2.3.0=compilePluginsBlocksPluginClasspathElements,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-stdlib:2.0.21=compileOnlyDependenciesMetadata +org.jetbrains.kotlin:kotlin-stdlib:2.3.0=bcv-rt-jvm-cp-resolver,compileClasspath,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath,testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-tooling-core:2.3.0=kotlinBuildToolsApiClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains:annotations:13.0=bcv-rt-jvm-cp-resolver,compileClasspath,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath,testCompileClasspath,testRuntimeClasspath org.ow2.asm:asm-tree:9.6=bcv-rt-jvm-cp-resolver org.ow2.asm:asm:9.6=bcv-rt-jvm-cp-resolver -empty=annotationProcessor,apiDependenciesMetadata,implementationDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDefExtensions,runtimeClasspath,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDefExtensions +empty=annotationProcessor,apiDependenciesMetadata,implementationDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDefExtensions,runtimeClasspath,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testImplementationDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDefExtensions diff --git a/mps-gradle-plugin/api/mps-gradle-plugin.api b/mps-gradle-plugin/api/mps-gradle-plugin.api index 38a68a2..2a0a8d5 100644 --- a/mps-gradle-plugin/api/mps-gradle-plugin.api +++ b/mps-gradle-plugin/api/mps-gradle-plugin.api @@ -15,12 +15,14 @@ public final class de/itemis/mps/gradle/CommonPlugin : org/gradle/api/Plugin { public final class de/itemis/mps/gradle/EnvironmentKind : java/lang/Enum { public static final field IDEA Lde/itemis/mps/gradle/EnvironmentKind; public static final field MPS Lde/itemis/mps/gradle/EnvironmentKind; + public static fun getEntries ()Lkotlin/enums/EnumEntries; public static fun valueOf (Ljava/lang/String;)Lde/itemis/mps/gradle/EnvironmentKind; public static fun values ()[Lde/itemis/mps/gradle/EnvironmentKind; } public class de/itemis/mps/gradle/GenerateLibrariesXml : org/gradle/api/DefaultTask, groovy/lang/GroovyObject { public static synthetic field __$stMC Z + public static synthetic fun $getLookup ()Ljava/lang/invoke/MethodHandles$Lookup; protected synthetic fun $getStaticMetaClass ()Lgroovy/lang/MetaClass; public fun ()V public fun generate ()Ljava/lang/Object; @@ -36,6 +38,7 @@ public class de/itemis/mps/gradle/GenerateLibrariesXml : org/gradle/api/DefaultT public class de/itemis/mps/gradle/Pom : groovy/lang/GroovyObject { public static synthetic field __$stMC Z + public static synthetic fun $getLookup ()Ljava/lang/invoke/MethodHandles$Lookup; protected synthetic fun $getStaticMetaClass ()Lgroovy/lang/MetaClass; public fun ()V public fun getMetaClass ()Lgroovy/lang/MetaClass; @@ -167,19 +170,19 @@ public abstract class de/itemis/mps/gradle/tasks/MpsMigrate : org/gradle/api/Def public final fun getProjectLocations ()Lorg/gradle/api/file/ConfigurableFileCollection; } -public class de/itemis/mps/gradle/tasks/Remigrate : org/gradle/api/tasks/JavaExec, de/itemis/mps/gradle/tasks/MpsProjectTask { - public fun (Lorg/gradle/api/model/ObjectFactory;Lorg/gradle/api/provider/ProviderFactory;)V +public abstract class de/itemis/mps/gradle/tasks/Remigrate : org/gradle/api/tasks/JavaExec, de/itemis/mps/gradle/tasks/MpsProjectTask { + public fun ()V public final fun excludeModuleMigration (Ljava/lang/String;I)V public fun exec ()V - public final fun getAdditionalClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; + public abstract fun getAdditionalClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; protected final fun getAllProjectFiles ()Lorg/gradle/api/provider/Provider; - public final fun getExcludedModuleMigrations ()Lorg/gradle/api/provider/SetProperty; - public fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; - public fun getLogLevel ()Lorg/gradle/api/provider/Property; - public fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; - public fun getMpsVersion ()Lorg/gradle/api/provider/Property; - public fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; - public fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; - public final fun getProjectLocations ()Lorg/gradle/api/file/ConfigurableFileCollection; + public abstract fun getExcludedModuleMigrations ()Lorg/gradle/api/provider/SetProperty; + public abstract fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; + public abstract fun getLogLevel ()Lorg/gradle/api/provider/Property; + public abstract fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; + public abstract fun getMpsVersion ()Lorg/gradle/api/provider/Property; + public abstract fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; + public abstract fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; + public abstract fun getProjectLocations ()Lorg/gradle/api/file/ConfigurableFileCollection; } diff --git a/mps-gradle-plugin/build.gradle.kts b/mps-gradle-plugin/build.gradle.kts index 80fa89e..63abd5e 100644 --- a/mps-gradle-plugin/build.gradle.kts +++ b/mps-gradle-plugin/build.gradle.kts @@ -1,12 +1,8 @@ -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.dsl.KotlinVersion - plugins { groovy `java-gradle-plugin` `kotlin-dsl` `maven-publish` - kotlin("jvm") version libs.versions.kotlin alias(libs.plugins.kotlin.compatibility.validator) } @@ -27,7 +23,6 @@ dependencyLocking { dependencies { api(libs.itemis.gradle.git.based.versioning) api("de.itemis.mps:mps-gradle-plugin-api") - implementation(libs.kotlin.stdlib) implementation(libs.swiftzer.semver) implementation(libs.itemis.gradle.build.backends.launcher) testImplementation(libs.junit) @@ -104,14 +99,12 @@ publishing { } java { - targetCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_17 withSourcesJar() } kotlin { compilerOptions { - jvmTarget = JvmTarget.fromTarget(libs.versions.kotlinJvmTarget.get()) - apiVersion = KotlinVersion.fromVersion(libs.versions.kotlinApi.get()) allWarningsAsErrors = true } } diff --git a/mps-gradle-plugin/gradle.lockfile b/mps-gradle-plugin/gradle.lockfile index 7c8e6fe..cdc921d 100644 --- a/mps-gradle-plugin/gradle.lockfile +++ b/mps-gradle-plugin/gradle.lockfile @@ -1,35 +1,39 @@ # This is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. -de.itemis.mps.build-backends:launcher:2.8.0.171.f987265=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath -junit:junit:4.13.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath -net.swiftzer.semver:semver:1.1.2=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath -org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath -org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-assignment-compiler-plugin-embeddable:2.0.21=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest -org.jetbrains.kotlin:kotlin-build-common:2.0.21=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-build-tools-api:2.0.21=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-build-tools-impl:2.0.21=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-compiler-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-compiler-runner:2.0.21=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-daemon-client:2.0.21=kotlinBuildToolsApiClasspath -org.jetbrains.kotlin:kotlin-daemon-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:2.0.21=kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-metadata-jvm:2.0.21=bcv-rt-jvm-cp-resolver +de.itemis.mps.build-backends:launcher:2.8.0.171.f987265=compileClasspath,precompiledScriptPluginAccessorsGenerationClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +io.github.java-diff-utils:java-diff-utils:4.12=kotlinInternalAbiValidation +junit:junit:4.13.2=testCompileClasspath,testRuntimeClasspath +net.swiftzer.semver:semver:1.1.2=compileClasspath,precompiledScriptPluginAccessorsGenerationClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:abi-tools-api:2.3.0=kotlinInternalAbiValidation +org.jetbrains.kotlin:abi-tools:2.3.0=kotlinInternalAbiValidation +org.jetbrains.kotlin:kotlin-assignment-compiler-plugin-embeddable:2.3.0=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-build-tools-api:2.3.0=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-build-tools-compat:2.3.0=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-build-tools-impl:2.3.0=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-compiler-embeddable:2.3.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-compiler-runner:2.3.0=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-daemon-client:2.3.0=kotlinBuildToolsApiClasspath +org.jetbrains.kotlin:kotlin-daemon-embeddable:2.3.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-klib-abi-reader:2.3.0=kotlinInternalAbiValidation +org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:2.3.0=kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-metadata-jvm:2.3.0=bcv-rt-jvm-cp-resolver,kotlinInternalAbiValidation org.jetbrains.kotlin:kotlin-native-prebuilt:2.0.21=kotlinNativeBundleConfiguration org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-reflect:2.0.21=compileClasspath,compileOnlyDependenciesMetadata,embeddedKotlin,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath -org.jetbrains.kotlin:kotlin-sam-with-receiver-compiler-plugin-embeddable:2.0.21=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest -org.jetbrains.kotlin:kotlin-script-runtime:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath -org.jetbrains.kotlin:kotlin-scripting-common:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest -org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest -org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest -org.jetbrains.kotlin:kotlin-scripting-jvm:2.0.21=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest -org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10=implementationDependenciesMetadata,runtimeClasspath -org.jetbrains.kotlin:kotlin-stdlib:1.7.10=implementationDependenciesMetadata,runtimeClasspath -org.jetbrains.kotlin:kotlin-stdlib:2.0.21=bcv-rt-jvm-cp-resolver,compileClasspath,compileOnlyDependenciesMetadata,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains:annotations:13.0=bcv-rt-jvm-cp-resolver,compileClasspath,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,implementationDependenciesMetadata,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-reflect:2.0.21=compileOnlyDependenciesMetadata +org.jetbrains.kotlin:kotlin-reflect:2.3.0=compileClasspath,embeddedKotlin,precompiledScriptPluginAccessorsGenerationClasspath,testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-sam-with-receiver-compiler-plugin-embeddable:2.3.0=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-script-runtime:2.3.0=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath +org.jetbrains.kotlin:kotlin-scripting-common:2.3.0=compilePluginsBlocksPluginClasspathElements,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:2.3.0=compilePluginsBlocksPluginClasspathElements,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:2.3.0=compilePluginsBlocksPluginClasspathElements,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-scripting-jvm:2.3.0=compilePluginsBlocksPluginClasspathElements,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest +org.jetbrains.kotlin:kotlin-stdlib:2.0.21=compileOnlyDependenciesMetadata +org.jetbrains.kotlin:kotlin-stdlib:2.3.0=bcv-rt-jvm-cp-resolver,compileClasspath,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath,precompiledScriptPluginAccessorsGenerationClasspath,testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-tooling-core:2.3.0=kotlinBuildToolsApiClasspath +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath +org.jetbrains:annotations:13.0=bcv-rt-jvm-cp-resolver,compileClasspath,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath,precompiledScriptPluginAccessorsGenerationClasspath,testCompileClasspath,testRuntimeClasspath org.ow2.asm:asm-tree:9.6=bcv-rt-jvm-cp-resolver org.ow2.asm:asm:9.6=bcv-rt-jvm-cp-resolver -empty=annotationProcessor,apiDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDefExtensions,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDefExtensions +empty=annotationProcessor,apiDependenciesMetadata,implementationDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDefExtensions,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testImplementationDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDefExtensions diff --git a/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/GenerateLibrariesXml.groovy b/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/GenerateLibrariesXml.groovy index ba618d5..a63fa98 100644 --- a/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/GenerateLibrariesXml.groovy +++ b/mps-gradle-plugin/src/main/groovy/de/itemis/mps/gradle/GenerateLibrariesXml.groovy @@ -7,10 +7,14 @@ import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Optional import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.TaskAction +import org.gradle.work.DisableCachingByDefault +@DisableCachingByDefault(because = "Not worth caching: generates a small XML file from a properties file") class GenerateLibrariesXml extends DefaultTask { - @InputFile + @InputFile @PathSensitive(PathSensitivity.NONE) File defaults @Internal diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt index 62d8925..2634452 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt @@ -9,14 +9,16 @@ import org.gradle.api.provider.Property import org.gradle.api.tasks.* import org.gradle.jvm.toolchain.JavaLauncher import org.gradle.process.ExecOperations +import org.gradle.work.DisableCachingByDefault import javax.inject.Inject +@DisableCachingByDefault(because = "Runs an Ant script that builds MPS languages and has non-trivial, external outputs") abstract class RunAntScript : DefaultTask(), MpsTask { @Input lateinit var script: Any @Input var targets: List = emptyList() - @Optional @InputFiles + @Optional @Classpath var scriptClasspath: FileCollection? = null @Input var scriptArgs: List = emptyList() @@ -126,13 +128,15 @@ abstract class RunAntScript : DefaultTask(), MpsTask { } } +@DisableCachingByDefault(because = "Runs an Ant script that builds MPS languages and has non-trivial, external outputs") abstract class BuildLanguages : RunAntScript() { init { targets = listOf("clean", "generate", "assemble") } } - abstract class TestLanguages : RunAntScript() { +@DisableCachingByDefault(because = "Runs an Ant script that tests MPS languages and has non-trivial, external outputs") +abstract class TestLanguages : RunAntScript() { init { targets = listOf("clean", "generate", "assemble", "check") } diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt index 5b46100..043650a 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt @@ -66,6 +66,7 @@ abstract class MpsMigrate @Inject constructor( @get:InputFiles @get:IgnoreEmptyDirectories @get:SkipWhenEmpty + @get:PathSensitive(PathSensitivity.RELATIVE) protected val allProjectFiles = providerFactory.provider { effectiveProjectLocations().flatMap { objectFactory.fileTree().from(it) } } diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt index a654d7f..7bdc7dd 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt @@ -11,68 +11,62 @@ import org.gradle.api.file.Directory import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileCollection import org.gradle.api.logging.LogLevel -import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property -import org.gradle.api.provider.ProviderFactory import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.* -import org.gradle.kotlin.dsl.mapProperty import org.gradle.kotlin.dsl.newInstance -import org.gradle.kotlin.dsl.property -import org.gradle.kotlin.dsl.setProperty import org.gradle.process.CommandLineArgumentProvider -import javax.inject.Inject @Incubating @UntrackedTask(because = "Operates 'in place'") -open class Remigrate @Inject constructor( - private val objectFactory: ObjectFactory, - providerFactory: ProviderFactory -) : JavaExec(), MpsProjectTask { +abstract class Remigrate : JavaExec(), MpsProjectTask { @get:Input - override val logLevel: Property = objectFactory.property().convention(project.gradle.startParameter.logLevel) + abstract override val logLevel: Property @get:Internal("covered by mpsVersion and classpath") - override val mpsHome: DirectoryProperty = objectFactory.directoryProperty() + abstract override val mpsHome: DirectoryProperty @get:Input @get:Optional - override val mpsVersion: Property = objectFactory.property() - .convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) + abstract override val mpsVersion: Property @get:Internal("covered by allProjectFiles") - override val projectLocation: DirectoryProperty = objectFactory.directoryProperty() + abstract override val projectLocation: DirectoryProperty @get:Internal("covered by allProjectFiles") - val projectLocations: ConfigurableFileCollection = objectFactory.fileCollection() + abstract val projectLocations: ConfigurableFileCollection @get:InputFiles @get:SkipWhenEmpty @get:IgnoreEmptyDirectories + @get:PathSensitive(PathSensitivity.RELATIVE) protected val allProjectFiles = providerFactory.provider { effectiveProjectLocations().flatMap { objectFactory.fileTree().from(it) } } @get:Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") - override val folderMacros: MapProperty = objectFactory.mapProperty() + abstract override val folderMacros: MapProperty @get:Classpath - override val pluginRoots: ConfigurableFileCollection = objectFactory.fileCollection() + abstract override val pluginRoots: ConfigurableFileCollection @get:Internal - val additionalClasspath: ConfigurableFileCollection = - objectFactory.fileCollection().from(initialBackendClasspath()) + abstract val additionalClasspath: ConfigurableFileCollection @get:Input - val excludedModuleMigrations: SetProperty = objectFactory.setProperty() + abstract val excludedModuleMigrations: SetProperty fun excludeModuleMigration(language: String, version: Int) { excludedModuleMigrations.add(ExcludedModuleMigration(language, version)) } init { + logLevel.convention(project.gradle.startParameter.logLevel) + mpsVersion.convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) + additionalClasspath.from(mpsHome.asFileTree.matching { include("lib/**/*.jar") }) + val backendBuilder: MpsBackendBuilder = project.objects.newInstance(MpsBackendBuilder::class) backendBuilder.withMpsHomeDirectory(mpsHome).withMpsVersion(mpsVersion).configure(this) @@ -135,8 +129,4 @@ open class Remigrate @Inject constructor( } return if (hasMultiple) projectLocations else objectFactory.fileCollection().from(projectLocation) } - - private fun initialBackendClasspath() = mpsHome.asFileTree.matching { - include("lib/**/*.jar") - } } From 576a4f8d43795091873cf0cb3ade175cb8049ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 19:07:54 +0200 Subject: [PATCH 29/44] Fix Renovate regex managers for test-file versions Two issues prevented the custom regex managers from working: 1. config:recommended sets ignorePaths including **/test/**, so Renovate silently skipped every file under src/test/kotlin. The ignorePaths list is cleared since none of the presets' entries correspond to paths that exist in this repository. 2. com.jetbrains:mps is not on Maven Central but on artifacts.itemis.cloud; the registryUrlTemplate now points there. Verified locally with renovate --platform=local: both the foojay plugin lookup and the MPS lookup resolve and produce update branches. Co-Authored-By: Claude Opus 4.7 (1M context) --- renovate.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index ef87c82..65db60c 100644 --- a/renovate.json +++ b/renovate.json @@ -4,6 +4,7 @@ "config:recommended" ], "forkProcessing": "enabled", + "ignorePaths": [], "customManagers": [ { "customType": "regex", @@ -29,7 +30,8 @@ "mps\\(\"com\\.jetbrains:mps:(?[^\"]+)\"\\)" ], "depNameTemplate": "com.jetbrains:mps", - "datasourceTemplate": "maven" + "datasourceTemplate": "maven", + "registryUrlTemplate": "https://artifacts.itemis.cloud/repository/maven-mps" } ] } From b8aa069adaa87f2d009f6343748ca8100070d5ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 19:20:14 +0200 Subject: [PATCH 30/44] Extract test MPS version into a single constant All integration tests that spin up an MPS instance now read their version from support.MPS_VERSION instead of hardcoding it in-line. This folds five call sites (three different versions: 2021.3.2, 2021.3.3, 2021.3.4) into one. Settling on 2021.3.4 for consistency; migration tests that previously pinned 2021.3.2 now share the same version as the rest. The Renovate custom manager for com.jetbrains:mps is narrowed to the new TestVersions.kt file and matches the const val, so updates go through a single well-named PR rather than several per-file ones. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/test/kotlin/support/TestVersions.kt | 7 +++++++ .../kotlin/test/codeexecution/MpsExecuteTaskTest.kt | 9 +++++---- .../src/test/kotlin/test/migration/RemigrateTest.kt | 3 ++- .../test/kotlin/test/migration/RunMigrationsTest.kt | 3 ++- .../kotlin/test/modelchecking/MpsCheckTaskTest.kt | 11 ++++++----- .../test/modelgeneration/MpsGenerateTaskTest.kt | 9 +++++---- renovate.json | 6 +++--- 7 files changed, 30 insertions(+), 18 deletions(-) create mode 100644 mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt diff --git a/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt b/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt new file mode 100644 index 0000000..6cc480a --- /dev/null +++ b/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt @@ -0,0 +1,7 @@ +package support + +/** + * MPS version used by integration tests that spin up an MPS instance (model check, generate, execute, migrate, ...). + * Kept in a single place so Renovate can bump it. + */ +const val MPS_VERSION = "2021.3.4" diff --git a/mps-gradle-plugin/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt b/mps-gradle-plugin/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt index 236a0e5..b4dae31 100644 --- a/mps-gradle-plugin/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt +++ b/mps-gradle-plugin/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt @@ -7,6 +7,7 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import support.MPS_VERSION import support.extractTestProject import java.io.File @@ -35,7 +36,7 @@ class MpsExecuteTaskTest { } """.trimIndent() - private fun buildScriptBoilerplate(mpsVersion: String) = """ + private fun buildScriptBoilerplate() = """ import de.itemis.mps.gradle.tasks.MpsExecute import de.itemis.mps.gradle.tasks.MpsGenerate @@ -51,7 +52,7 @@ class MpsExecuteTaskTest { val mps = configurations.create("mps") dependencies { - mps("com.jetbrains:mps:$mpsVersion") + mps("com.jetbrains:mps:$MPS_VERSION") } val resolveMps by tasks.registering(Sync::class) { @@ -83,7 +84,7 @@ class MpsExecuteTaskTest { @Test fun `execute with Project`() { - buildFile.writeText(buildScriptBoilerplate("2021.3.4") + """ + buildFile.writeText(buildScriptBoilerplate() + """ execute { module = "NewSolution" className = "NewSolution.myModel.MyClass" @@ -98,7 +99,7 @@ class MpsExecuteTaskTest { @Test fun `execute with Project and args`() { - buildFile.writeText(buildScriptBoilerplate("2021.3.4") + """ + buildFile.writeText(buildScriptBoilerplate() + """ execute { module = "NewSolution" className = "NewSolution.myModel.MyClass" diff --git a/mps-gradle-plugin/src/test/kotlin/test/migration/RemigrateTest.kt b/mps-gradle-plugin/src/test/kotlin/test/migration/RemigrateTest.kt index b791299..2775440 100644 --- a/mps-gradle-plugin/src/test/kotlin/test/migration/RemigrateTest.kt +++ b/mps-gradle-plugin/src/test/kotlin/test/migration/RemigrateTest.kt @@ -7,6 +7,7 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import support.MPS_VERSION import support.extractTestProject import java.io.File @@ -54,7 +55,7 @@ class RemigrateTest { val mps = configurations.create("mps") dependencies { - mps("com.jetbrains:mps:2021.3.2") + mps("com.jetbrains:mps:$MPS_VERSION") } val resolveMps by tasks.registering(Sync::class) { diff --git a/mps-gradle-plugin/src/test/kotlin/test/migration/RunMigrationsTest.kt b/mps-gradle-plugin/src/test/kotlin/test/migration/RunMigrationsTest.kt index c5d39fe..daf6beb 100644 --- a/mps-gradle-plugin/src/test/kotlin/test/migration/RunMigrationsTest.kt +++ b/mps-gradle-plugin/src/test/kotlin/test/migration/RunMigrationsTest.kt @@ -7,6 +7,7 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import support.MPS_VERSION import support.extractTestProject import java.io.File @@ -48,7 +49,7 @@ class RunMigrationsTest { val mps = configurations.create("mps") dependencies { - mps("com.jetbrains:mps:2021.3.2") + mps("com.jetbrains:mps:$MPS_VERSION") } val resolveMps by tasks.registering(Sync::class) { diff --git a/mps-gradle-plugin/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt b/mps-gradle-plugin/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt index 84e5290..5b8dfa2 100644 --- a/mps-gradle-plugin/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt +++ b/mps-gradle-plugin/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt @@ -9,6 +9,7 @@ import org.junit.Assert import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import support.MPS_VERSION import support.extractTestProject class MpsCheckTaskTest { @@ -22,7 +23,7 @@ class MpsCheckTaskTest { } """.trimIndent() - private fun buildScriptBoilerplate(mpsVersion: String) = """ + private fun buildScriptBoilerplate() = """ import de.itemis.mps.gradle.tasks.MpsCheck plugins { @@ -37,7 +38,7 @@ class MpsCheckTaskTest { val mps = configurations.create("mps") dependencies { - mps("com.jetbrains:mps:$mpsVersion") + mps("com.jetbrains:mps:$MPS_VERSION") } val resolveMps by tasks.registering(Sync::class) { @@ -55,7 +56,7 @@ class MpsCheckTaskTest { extractTestProject("test-project", mpsTestPrjLocation) settingsFile.writeText(settingsScriptBoilerplate()) - buildFile.writeText(buildScriptBoilerplate("2021.3.3") + """ + buildFile.writeText(buildScriptBoilerplate() + """ val checkProject by tasks.registering(MpsCheck::class) { mpsHome = layout.dir(resolveMps.map { it.destinationDir }) junitFile = layout.buildDirectory.file("output.xml") @@ -77,7 +78,7 @@ class MpsCheckTaskTest { extractTestProject("test-project", mpsTestPrjLocation) settingsFile.writeText(settingsScriptBoilerplate()) - buildFile.writeText(buildScriptBoilerplate("2021.3.3") + """ + buildFile.writeText(buildScriptBoilerplate() + """ val checkProject by tasks.registering(MpsCheck::class) { mpsHome = layout.dir(resolveMps.map { it.destinationDir }) projectLocation = file("mps-prj") @@ -102,7 +103,7 @@ class MpsCheckTaskTest { extractTestProject("test-project", mpsTestPrjLocation) settingsFile.writeText(settingsScriptBoilerplate()) - buildFile.writeText(buildScriptBoilerplate("2021.3.3") + """ + buildFile.writeText(buildScriptBoilerplate() + """ val checkProject by tasks.registering(MpsCheck::class) { mpsHome = layout.dir(resolveMps.map { it.destinationDir }) projectLocation = file("mps-prj") diff --git a/mps-gradle-plugin/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt b/mps-gradle-plugin/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt index 801ef17..dbcf598 100644 --- a/mps-gradle-plugin/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt +++ b/mps-gradle-plugin/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt @@ -9,6 +9,7 @@ import org.junit.Assert import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import support.MPS_VERSION import support.extractTestProject class MpsGenerateTaskTest { @@ -22,7 +23,7 @@ class MpsGenerateTaskTest { } """.trimIndent() - private fun buildScriptBoilerplate(mpsVersion: String) = """ + private fun buildScriptBoilerplate() = """ import de.itemis.mps.gradle.tasks.MpsGenerate plugins { @@ -37,7 +38,7 @@ class MpsGenerateTaskTest { val mps = configurations.create("mps") dependencies { - mps("com.jetbrains:mps:$mpsVersion") + mps("com.jetbrains:mps:$MPS_VERSION") } val resolveMps by tasks.registering(Sync::class) { @@ -55,7 +56,7 @@ class MpsGenerateTaskTest { extractTestProject("test-project", mpsTestPrjLocation) settingsFile.writeText(settingsScriptBoilerplate()) - buildFile.writeText(buildScriptBoilerplate("2021.3.3") + """ + buildFile.writeText(buildScriptBoilerplate() + """ val generateProject by tasks.registering(MpsGenerate::class) { mpsHome = layout.dir(resolveMps.map { it.destinationDir }) } @@ -76,7 +77,7 @@ class MpsGenerateTaskTest { extractTestProject("test-project", mpsTestPrjLocation) settingsFile.writeText(settingsScriptBoilerplate()) - buildFile.writeText(buildScriptBoilerplate("2021.3.3") + """ + buildFile.writeText(buildScriptBoilerplate() + """ val generateProject by tasks.registering(MpsGenerate::class) { mpsHome = layout.dir(resolveMps.map { it.destinationDir }) projectLocation = file("mps-prj") diff --git a/renovate.json b/renovate.json index 65db60c..957cc4e 100644 --- a/renovate.json +++ b/renovate.json @@ -22,12 +22,12 @@ }, { "customType": "regex", - "description": "Update com.jetbrains:mps versions embedded in Kotlin test sources (used in generated Gradle scripts).", + "description": "Update the MPS_VERSION constant used by tests to spin up an MPS instance.", "managerFilePatterns": [ - "/^mps-gradle-plugin/src/test/kotlin/.*\\.kt$/" + "/^mps-gradle-plugin/src/test/kotlin/support/TestVersions\\.kt$/" ], "matchStrings": [ - "mps\\(\"com\\.jetbrains:mps:(?[^\"]+)\"\\)" + "const val MPS_VERSION\\s*=\\s*\"(?[^\"]+)\"" ], "depNameTemplate": "com.jetbrains:mps", "datasourceTemplate": "maven", From 95662181c623959e976635d40299f64d9a21fa00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 19:53:42 +0200 Subject: [PATCH 31/44] Add aggregating tasks to the root project --- build.gradle.kts | 9 +++++++++ mps-gradle-plugin/settings.gradle.kts | 3 --- settings.gradle.kts | 2 -- 3 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..be69aee --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,9 @@ +tasks.register("build") { + description = "Aggregates the build task of each included build." + dependsOn(gradle.includedBuilds.map { it.task(":build") }) +} + +tasks.register("publishToMavenLocal") { + description = "Aggregates the publishToMavenLocal task of each included build." + dependsOn(gradle.includedBuilds.map { it.task(":publishToMavenLocal") }) +} diff --git a/mps-gradle-plugin/settings.gradle.kts b/mps-gradle-plugin/settings.gradle.kts index 75c4133..325a9d8 100644 --- a/mps-gradle-plugin/settings.gradle.kts +++ b/mps-gradle-plugin/settings.gradle.kts @@ -10,8 +10,5 @@ dependencyResolutionManagement { } } -rootProject.name = "mps-gradle-plugin" - includeBuild("../git-based-versioning") - includeBuild("../mps-gradle-plugin-api") diff --git a/settings.gradle.kts b/settings.gradle.kts index eb4570d..564035e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -9,7 +9,5 @@ plugins { rootProject.name = "mps-gradle-plugin" includeBuild("git-based-versioning") - includeBuild("mps-gradle-plugin-api") - includeBuild("mps-gradle-plugin") From 0bdbacbaa67fcea96f6e7c86ad8c6a2654047323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 20:02:52 +0200 Subject: [PATCH 32/44] Bump MPS version in tests to 2025.1.2 2025.1 no longer accepts arbitrary objects as log messages. Add explicit toString() calls. Remove Java 11 provisioning in the GitHub workflow. --- .github/workflows/gradle.yml | 6 ----- .../src/test/kotlin/support/TestVersions.kt | 2 +- .../resources/test-project/.mps/migration.xml | 11 +++++++++ .../test/resources/test-project/.mps/vcs.xml | 1 + .../solutions/NewSolution/NewSolution.msd | 11 ++++----- .../models/NewSolution.myModel.mps | 24 +++++++++++++------ 6 files changed, 35 insertions(+), 20 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 1bbd386..b0088f2 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -28,12 +28,6 @@ jobs: java: [ 17, 21 ] steps: - uses: actions/checkout@v4 - # Java 11 is always needed to run the tests because they use MPS 2021.x - - name: Set up Java 11 - uses: actions/setup-java@v3 - with: - distribution: temurin - java-version: 11 - uses: actions/setup-java@v3 with: distribution: temurin diff --git a/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt b/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt index 6cc480a..1164261 100644 --- a/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt +++ b/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt @@ -4,4 +4,4 @@ package support * MPS version used by integration tests that spin up an MPS instance (model check, generate, execute, migrate, ...). * Kept in a single place so Renovate can bump it. */ -const val MPS_VERSION = "2021.3.4" +const val MPS_VERSION = "2025.1.2" diff --git a/mps-gradle-plugin/src/test/resources/test-project/.mps/migration.xml b/mps-gradle-plugin/src/test/resources/test-project/.mps/migration.xml index e9a4b4b..31a52fb 100644 --- a/mps-gradle-plugin/src/test/resources/test-project/.mps/migration.xml +++ b/mps-gradle-plugin/src/test/resources/test-project/.mps/migration.xml @@ -1,6 +1,17 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/mps-gradle-plugin/src/test/resources/test-project/.mps/vcs.xml b/mps-gradle-plugin/src/test/resources/test-project/.mps/vcs.xml index 4fce1d8..c68f248 100644 --- a/mps-gradle-plugin/src/test/resources/test-project/.mps/vcs.xml +++ b/mps-gradle-plugin/src/test/resources/test-project/.mps/vcs.xml @@ -1,6 +1,7 @@ + \ No newline at end of file diff --git a/mps-gradle-plugin/src/test/resources/test-project/solutions/NewSolution/NewSolution.msd b/mps-gradle-plugin/src/test/resources/test-project/solutions/NewSolution/NewSolution.msd index 188f59c..78012f1 100644 --- a/mps-gradle-plugin/src/test/resources/test-project/solutions/NewSolution/NewSolution.msd +++ b/mps-gradle-plugin/src/test/resources/test-project/solutions/NewSolution/NewSolution.msd @@ -1,31 +1,30 @@ - + - + - 6354ebe7-c22a-4a0f-ac54-50b52ab9b065(JDK) 6ed54515-acc8-4d1e-a16c-9fd6cfe951ea(MPS.Core) - + - + - + diff --git a/mps-gradle-plugin/src/test/resources/test-project/solutions/NewSolution/models/NewSolution.myModel.mps b/mps-gradle-plugin/src/test/resources/test-project/solutions/NewSolution/models/NewSolution.myModel.mps index 6d4064b..b3d1980 100644 --- a/mps-gradle-plugin/src/test/resources/test-project/solutions/NewSolution/models/NewSolution.myModel.mps +++ b/mps-gradle-plugin/src/test/resources/test-project/solutions/NewSolution/models/NewSolution.myModel.mps @@ -51,7 +51,7 @@ - + @@ -61,7 +61,7 @@ - + @@ -73,7 +73,7 @@ - + @@ -123,8 +123,13 @@ - - + + + + + + + @@ -143,8 +148,13 @@ - - + + + + + + + From 2be70ca711a2fa97a1a748c5ed831c1b040ba970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 20:21:04 +0200 Subject: [PATCH 33/44] Extract foojay-resolver-convention version used by tests Same treatment as MPS_VERSION: five call sites in the generated settings scripts now read from support.FOOJAY_RESOLVER_CONVENTION_VERSION, and the Renovate custom manager is narrowed to match the const val in TestVersions.kt so updates land as one PR. Co-Authored-By: Claude Opus 4.7 (1M context) --- mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt | 6 ++++++ .../src/test/kotlin/test/MpsTaskInterfaceTest.kt | 3 ++- .../test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt | 3 ++- .../src/test/kotlin/test/migration/RemigrateTest.kt | 3 ++- .../src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt | 3 ++- .../test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt | 3 ++- renovate.json | 6 +++--- 7 files changed, 19 insertions(+), 8 deletions(-) diff --git a/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt b/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt index 1164261..857196e 100644 --- a/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt +++ b/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt @@ -5,3 +5,9 @@ package support * Kept in a single place so Renovate can bump it. */ const val MPS_VERSION = "2025.1.2" + +/** + * Version of the foojay-resolver-convention plugin applied in the settings scripts that tests generate. + * Kept in a single place so Renovate can bump it. + */ +const val FOOJAY_RESOLVER_CONVENTION_VERSION = "0.7.0" diff --git a/mps-gradle-plugin/src/test/kotlin/test/MpsTaskInterfaceTest.kt b/mps-gradle-plugin/src/test/kotlin/test/MpsTaskInterfaceTest.kt index b56afdb..9adfd4c 100644 --- a/mps-gradle-plugin/src/test/kotlin/test/MpsTaskInterfaceTest.kt +++ b/mps-gradle-plugin/src/test/kotlin/test/MpsTaskInterfaceTest.kt @@ -6,6 +6,7 @@ import org.hamcrest.MatcherAssert.assertThat import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import support.FOOJAY_RESOLVER_CONVENTION_VERSION class MpsTaskInterfaceTest { @Rule @@ -17,7 +18,7 @@ class MpsTaskInterfaceTest { testProjectDir.newFile("settings.gradle.kts").writeText( """ plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version ("0.7.0") + id("org.gradle.toolchains.foojay-resolver-convention") version ("$FOOJAY_RESOLVER_CONVENTION_VERSION") } """.trimIndent() ) diff --git a/mps-gradle-plugin/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt b/mps-gradle-plugin/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt index b4dae31..975f001 100644 --- a/mps-gradle-plugin/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt +++ b/mps-gradle-plugin/src/test/kotlin/test/codeexecution/MpsExecuteTaskTest.kt @@ -7,6 +7,7 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import support.FOOJAY_RESOLVER_CONVENTION_VERSION import support.MPS_VERSION import support.extractTestProject import java.io.File @@ -32,7 +33,7 @@ class MpsExecuteTaskTest { private fun settingsScriptBoilerplate() = """ plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version ("0.7.0") + id("org.gradle.toolchains.foojay-resolver-convention") version ("$FOOJAY_RESOLVER_CONVENTION_VERSION") } """.trimIndent() diff --git a/mps-gradle-plugin/src/test/kotlin/test/migration/RemigrateTest.kt b/mps-gradle-plugin/src/test/kotlin/test/migration/RemigrateTest.kt index 2775440..8c13b90 100644 --- a/mps-gradle-plugin/src/test/kotlin/test/migration/RemigrateTest.kt +++ b/mps-gradle-plugin/src/test/kotlin/test/migration/RemigrateTest.kt @@ -7,6 +7,7 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import support.FOOJAY_RESOLVER_CONVENTION_VERSION import support.MPS_VERSION import support.extractTestProject import java.io.File @@ -25,7 +26,7 @@ class RemigrateTest { settingsFile.writeText( """ plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version ("0.7.0") + id("org.gradle.toolchains.foojay-resolver-convention") version ("$FOOJAY_RESOLVER_CONVENTION_VERSION") } rootProject.name = "hello-world" """.trimIndent() diff --git a/mps-gradle-plugin/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt b/mps-gradle-plugin/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt index 5b8dfa2..13856e0 100644 --- a/mps-gradle-plugin/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt +++ b/mps-gradle-plugin/src/test/kotlin/test/modelchecking/MpsCheckTaskTest.kt @@ -9,6 +9,7 @@ import org.junit.Assert import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import support.FOOJAY_RESOLVER_CONVENTION_VERSION import support.MPS_VERSION import support.extractTestProject @@ -19,7 +20,7 @@ class MpsCheckTaskTest { private fun settingsScriptBoilerplate() = """ plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version ("0.7.0") + id("org.gradle.toolchains.foojay-resolver-convention") version ("$FOOJAY_RESOLVER_CONVENTION_VERSION") } """.trimIndent() diff --git a/mps-gradle-plugin/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt b/mps-gradle-plugin/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt index dbcf598..9e05d03 100644 --- a/mps-gradle-plugin/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt +++ b/mps-gradle-plugin/src/test/kotlin/test/modelgeneration/MpsGenerateTaskTest.kt @@ -9,6 +9,7 @@ import org.junit.Assert import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import support.FOOJAY_RESOLVER_CONVENTION_VERSION import support.MPS_VERSION import support.extractTestProject @@ -19,7 +20,7 @@ class MpsGenerateTaskTest { private fun settingsScriptBoilerplate() = """ plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version ("0.7.0") + id("org.gradle.toolchains.foojay-resolver-convention") version ("$FOOJAY_RESOLVER_CONVENTION_VERSION") } """.trimIndent() diff --git a/renovate.json b/renovate.json index 957cc4e..12c95d5 100644 --- a/renovate.json +++ b/renovate.json @@ -8,12 +8,12 @@ "customManagers": [ { "customType": "regex", - "description": "Update foojay-resolver-convention plugin pinned inside Kotlin test sources (used in generated Gradle scripts).", + "description": "Update the FOOJAY_RESOLVER_CONVENTION_VERSION constant used by tests.", "managerFilePatterns": [ - "/^mps-gradle-plugin/src/test/kotlin/.*\\.kt$/" + "/^mps-gradle-plugin/src/test/kotlin/support/TestVersions\\.kt$/" ], "matchStrings": [ - "id\\(\"org\\.gradle\\.toolchains\\.foojay-resolver-convention\"\\)\\s*version\\s*\\(\"(?[^\"]+)\"\\)" + "const val FOOJAY_RESOLVER_CONVENTION_VERSION\\s*=\\s*\"(?[^\"]+)\"" ], "depNameTemplate": "org.gradle.toolchains.foojay-resolver-convention", "packageNameTemplate": "org.gradle.toolchains.foojay-resolver-convention:org.gradle.toolchains.foojay-resolver-convention.gradle.plugin", From f6c7c24f33eab046372c7d1032a9e56d73ac1cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 21:35:30 +0200 Subject: [PATCH 34/44] Rewrite mps-gradle-plugin-api in Java The api subproject now holds two plain Java 17 interfaces instead of Kotlin ones. Drops kotlin-dsl, the binary-compatibility-validator (which requires Kotlin), and the Kotlin compileOnly/stdlib wiring; adds compileOnly(gradleApi()). Kotlin does not allow `override val x: T` to override a Java `getX(): T` method, so every subclass in mps-gradle-plugin that implemented MpsTask / MpsProjectTask members is converted to `abstract override fun getX()`. This goes hand in hand with the abstract-property pattern Gradle's managed types support: the objectFactory.property() boilerplate in the property declarations is dropped and conventions move to init blocks. MpsMigrate extends DefaultTask (which doesn't expose objectFactory/providerFactory), so it gets abstract @Inject getters for those instead of a constructor. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../api/mps-gradle-plugin-api.api | 13 --- mps-gradle-plugin-api/build.gradle.kts | 61 ++++++------ mps-gradle-plugin-api/gradle.lockfile | 8 +- .../mps/gradle/tasks/MpsProjectTask.java | 54 +++++++++++ .../de/itemis/mps/gradle/tasks/MpsTask.java | 35 +++++++ .../itemis/mps/gradle/tasks/MpsProjectTask.kt | 54 ----------- .../de/itemis/mps/gradle/tasks/MpsTask.kt | 39 -------- mps-gradle-plugin/api/mps-gradle-plugin.api | 92 ++++++++++--------- .../de/itemis/mps/gradle/RunAntScript.kt | 10 +- .../de/itemis/mps/gradle/tasks/MpsCheck.kt | 59 ++++++------ .../de/itemis/mps/gradle/tasks/MpsExecute.kt | 28 +++--- .../de/itemis/mps/gradle/tasks/MpsGenerate.kt | 57 ++++++------ .../de/itemis/mps/gradle/tasks/MpsMigrate.kt | 61 ++++++------ .../de/itemis/mps/gradle/tasks/Remigrate.kt | 26 +++--- 14 files changed, 297 insertions(+), 300 deletions(-) delete mode 100644 mps-gradle-plugin-api/api/mps-gradle-plugin-api.api create mode 100644 mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsProjectTask.java create mode 100644 mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsTask.java delete mode 100644 mps-gradle-plugin-api/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt delete mode 100644 mps-gradle-plugin-api/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt diff --git a/mps-gradle-plugin-api/api/mps-gradle-plugin-api.api b/mps-gradle-plugin-api/api/mps-gradle-plugin-api.api deleted file mode 100644 index c9b9977..0000000 --- a/mps-gradle-plugin-api/api/mps-gradle-plugin-api.api +++ /dev/null @@ -1,13 +0,0 @@ -public abstract interface class de/itemis/mps/gradle/tasks/MpsProjectTask : de/itemis/mps/gradle/tasks/MpsTask { - public abstract fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; - public abstract fun getLogLevel ()Lorg/gradle/api/provider/Property; - public abstract fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; - public abstract fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; -} - -public abstract interface class de/itemis/mps/gradle/tasks/MpsTask : org/gradle/api/Task { - public abstract fun getJavaLauncher ()Lorg/gradle/api/provider/Property; - public abstract fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; - public abstract fun getMpsVersion ()Lorg/gradle/api/provider/Property; -} - diff --git a/mps-gradle-plugin-api/build.gradle.kts b/mps-gradle-plugin-api/build.gradle.kts index 38d278b..8ded536 100644 --- a/mps-gradle-plugin-api/build.gradle.kts +++ b/mps-gradle-plugin-api/build.gradle.kts @@ -1,7 +1,6 @@ plugins { - `kotlin-dsl` + `java-library` `maven-publish` - alias(libs.plugins.kotlin.compatibility.validator) } group = "de.itemis.mps" @@ -16,6 +15,20 @@ dependencyLocking { lockAllConfigurations() } +dependencies { + compileOnly(gradleApi()) +} + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + withSourcesJar() +} + +tasks.withType().configureEach { + options.compilerArgs.addAll(listOf("-Xlint:all", "-Werror")) +} + publishing { repositories { val isSnapshot = project.version.toString().endsWith("SNAPSHOT") @@ -46,40 +59,32 @@ publishing { } } - publications.withType().configureEach { - versionMapping { - allVariants { - fromResolutionResult() - } - } - pom { - url = "https://github.com/mbeddr/mps-gradle-plugin" - licenses { - license { - name = "The Apache License, Version 2.0" - url = "https://www.apache.org/licenses/LICENSE-2.0.txt" + publications { + create("mavenJava") { + from(components["java"]) + versionMapping { + allVariants { + fromResolutionResult() } } - scm { - connection = "scm:git:git://github.com/mbeddr/mps-gradle-plugin.git" - developerConnection = "scm:git:ssh://github.com/mbeddr/mps-gradle-plugin.git" + pom { url = "https://github.com/mbeddr/mps-gradle-plugin" + licenses { + license { + name = "The Apache License, Version 2.0" + url = "https://www.apache.org/licenses/LICENSE-2.0.txt" + } + } + scm { + connection = "scm:git:git://github.com/mbeddr/mps-gradle-plugin.git" + developerConnection = "scm:git:ssh://github.com/mbeddr/mps-gradle-plugin.git" + url = "https://github.com/mbeddr/mps-gradle-plugin" + } } } } } -java { - targetCompatibility = JavaVersion.VERSION_17 - withSourcesJar() -} - -kotlin { - compilerOptions { - allWarningsAsErrors = true - } -} - tasks.register("setTeamCityBuildNumber") { doLast { println("##teamcity[buildNumber '$version']") diff --git a/mps-gradle-plugin-api/gradle.lockfile b/mps-gradle-plugin-api/gradle.lockfile index 308b86c..f4a90db 100644 --- a/mps-gradle-plugin-api/gradle.lockfile +++ b/mps-gradle-plugin-api/gradle.lockfile @@ -18,7 +18,7 @@ org.jetbrains.kotlin:kotlin-metadata-jvm:2.3.0=bcv-rt-jvm-cp-resolver,kotlinInte org.jetbrains.kotlin:kotlin-native-prebuilt:2.0.21=kotlinNativeBundleConfiguration org.jetbrains.kotlin:kotlin-reflect:1.6.10=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.jetbrains.kotlin:kotlin-reflect:2.0.21=compileOnlyDependenciesMetadata -org.jetbrains.kotlin:kotlin-reflect:2.3.0=compileClasspath,embeddedKotlin,testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-reflect:2.3.0=embeddedKotlin org.jetbrains.kotlin:kotlin-sam-with-receiver-compiler-plugin-embeddable:2.3.0=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-script-runtime:2.3.0=compilePluginsBlocksPluginClasspathElements,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath org.jetbrains.kotlin:kotlin-scripting-common:2.3.0=compilePluginsBlocksPluginClasspathElements,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest @@ -26,10 +26,10 @@ org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:2.3.0=compilePluginsBl org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:2.3.0=compilePluginsBlocksPluginClasspathElements,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-scripting-jvm:2.3.0=compilePluginsBlocksPluginClasspathElements,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-stdlib:2.0.21=compileOnlyDependenciesMetadata -org.jetbrains.kotlin:kotlin-stdlib:2.3.0=bcv-rt-jvm-cp-resolver,compileClasspath,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath,testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib:2.3.0=bcv-rt-jvm-cp-resolver,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath org.jetbrains.kotlin:kotlin-tooling-core:2.3.0=kotlinBuildToolsApiClasspath org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath -org.jetbrains:annotations:13.0=bcv-rt-jvm-cp-resolver,compileClasspath,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath,testCompileClasspath,testRuntimeClasspath +org.jetbrains:annotations:13.0=bcv-rt-jvm-cp-resolver,compilePluginsBlocksPluginClasspathElements,embeddedKotlin,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinInternalAbiValidation,kotlinKlibCommonizerClasspath org.ow2.asm:asm-tree:9.6=bcv-rt-jvm-cp-resolver org.ow2.asm:asm:9.6=bcv-rt-jvm-cp-resolver -empty=annotationProcessor,apiDependenciesMetadata,implementationDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDefExtensions,runtimeClasspath,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testImplementationDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDefExtensions +empty=annotationProcessor,apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDefExtensions,runtimeClasspath,testAnnotationProcessor,testApiDependenciesMetadata,testCompileClasspath,testCompileOnlyDependenciesMetadata,testImplementationDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDefExtensions,testRuntimeClasspath diff --git a/mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsProjectTask.java b/mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsProjectTask.java new file mode 100644 index 0000000..79ae473 --- /dev/null +++ b/mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsProjectTask.java @@ -0,0 +1,54 @@ +package de.itemis.mps.gradle.tasks; + +import org.gradle.api.Incubating; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.Directory; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.logging.LogLevel; +import org.gradle.api.provider.MapProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Classpath; +import org.gradle.api.tasks.Console; +import org.gradle.api.tasks.Internal; + +/** + * A Gradle task that operates on one or more MPS projects. + * + *

Use {@link org.gradle.api.tasks.TaskCollection#withType(Class)} to configure all MPS project tasks at once: + * + *

{@code
+ * tasks.withType(MpsProjectTask.class).configureEach(task -> {
+ *     task.getMpsHome().set(layout.getProjectDirectory().dir("mps"));
+ *     task.getProjectLocation().set(layout.getProjectDirectory().dir("my-mps-project"));
+ *     task.getPluginRoots().from(task.getMpsHome().dir("plugins"));
+ * });
+ * }
+ */ +@Incubating +public interface MpsProjectTask extends MpsTask { + /** + * The MPS project directory. Convention: the Gradle project directory (but no convention is set on + * multi-project tasks like MpsMigrate and Remigrate, so that the mutual exclusivity check with + * {@code projectLocations} works correctly). + */ + @Internal("too coarse to be used as input") + DirectoryProperty getProjectLocation(); + + /** + * Root directories containing MPS plugins to load. + */ + @Classpath + ConfigurableFileCollection getPluginRoots(); + + /** + * Folder macros (path variables) to pass to MPS. Keys are macro names, values are directories. + */ + @Internal("not considered input") + MapProperty getFolderMacros(); + + /** + * Log level for the MPS backend process. + */ + @Console + Property getLogLevel(); +} diff --git a/mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsTask.java b/mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsTask.java new file mode 100644 index 0000000..11c782e --- /dev/null +++ b/mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsTask.java @@ -0,0 +1,35 @@ +package de.itemis.mps.gradle.tasks; + +import org.gradle.api.Incubating; +import org.gradle.api.Task; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.Nested; +import org.gradle.jvm.toolchain.JavaLauncher; + +/** + * A Gradle task that operates on an MPS installation. + */ +@Incubating +public interface MpsTask extends Task { + /** + * The MPS installation directory. + */ + @Internal("not considered an input by itself") + DirectoryProperty getMpsHome(); + + /** + * The MPS version string (e.g. "2021.3.3"). Detected automatically from {@link #getMpsHome()} if not set + * explicitly. + */ + @Input + Property getMpsVersion(); + + /** + * The Java launcher to use for running MPS. Each MPS version requires a specific Java version. + */ + @Nested + Property getJavaLauncher(); +} diff --git a/mps-gradle-plugin-api/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt b/mps-gradle-plugin-api/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt deleted file mode 100644 index 77d951e..0000000 --- a/mps-gradle-plugin-api/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsProjectTask.kt +++ /dev/null @@ -1,54 +0,0 @@ -package de.itemis.mps.gradle.tasks - -import org.gradle.api.Incubating -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.Directory -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.logging.LogLevel -import org.gradle.api.provider.MapProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Classpath -import org.gradle.api.tasks.Console -import org.gradle.api.tasks.Internal - -/** - * A Gradle task that operates on one or more MPS projects. - * - * Use [org.gradle.api.tasks.TaskCollection.withType] to configure all MPS project tasks at once: - * - * ```kotlin - * tasks.withType().configureEach { - * mpsHome = layout.projectDirectory.dir("mps") - * projectLocation = layout.projectDirectory.dir("my-mps-project") - * pluginRoots.from(mpsHome.dir("plugins")) - * } - * ``` - */ -@Incubating -interface MpsProjectTask : MpsTask { - /** - * The MPS project directory. Convention: the Gradle project directory (but no convention is set on - * multi-project tasks like MpsMigrate and Remigrate, so that the mutual exclusivity check with - * [projectLocations][MpsMigrate.projectLocations] works correctly). - */ - @get:Internal("too coarse to be used as input") - val projectLocation: DirectoryProperty - - /** - * Root directories containing MPS plugins to load. - */ - @get:Classpath - val pluginRoots: ConfigurableFileCollection - - /** - * Folder macros (path variables) to pass to MPS. Keys are macro names, values are directories. - */ - @get:Internal("not considered input") - val folderMacros: MapProperty - - /** - * Log level for the MPS backend process. - */ - @get:Console - val logLevel: Property -} diff --git a/mps-gradle-plugin-api/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt b/mps-gradle-plugin-api/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt deleted file mode 100644 index 633c8b8..0000000 --- a/mps-gradle-plugin-api/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsTask.kt +++ /dev/null @@ -1,39 +0,0 @@ -package de.itemis.mps.gradle.tasks - -import org.gradle.api.Incubating -import org.gradle.api.Task -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.Internal -import org.gradle.api.tasks.Nested -import org.gradle.api.tasks.UntrackedTask -import org.gradle.jvm.toolchain.JavaLauncher -import org.gradle.work.DisableCachingByDefault - -/** - * A Gradle task that operates on an MPS installation. - */ -@Incubating -interface MpsTask : Task { - /** - * The MPS installation directory. - */ - @get:Internal("not considered an input by itself") - val mpsHome: DirectoryProperty - - /** - * The MPS version string (e.g. "2021.3.3"). Detected automatically from [mpsHome] if not set explicitly. - */ - @get:Input - val mpsVersion: Property - - /** - * The Java launcher to use for running MPS. Each MPS version requires a specific Java version. - * - * Declared as a function rather than a Kotlin property to avoid a platform declarations clash - * with [org.gradle.api.tasks.JavaExec.getJavaLauncher]. - */ - @Nested - fun getJavaLauncher(): Property -} diff --git a/mps-gradle-plugin/api/mps-gradle-plugin.api b/mps-gradle-plugin/api/mps-gradle-plugin.api index 2a0a8d5..561a21c 100644 --- a/mps-gradle-plugin/api/mps-gradle-plugin.api +++ b/mps-gradle-plugin/api/mps-gradle-plugin.api @@ -57,7 +57,7 @@ public abstract class de/itemis/mps/gradle/RunAntScript : org/gradle/api/Default public final fun getIncludeDefaultArgs ()Z public final fun getIncludeDefaultClasspath ()Z public final fun getIncremental ()Z - public fun getJavaLauncher ()Lorg/gradle/api/provider/Property; + public abstract fun getJavaLauncher ()Lorg/gradle/api/provider/Property; public abstract fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; public final fun getScript ()Ljava/lang/Object; public final fun getScriptArgs ()Ljava/util/List; @@ -94,29 +94,29 @@ public final class de/itemis/mps/gradle/tasks/ExcludedModuleMigration { public abstract class de/itemis/mps/gradle/tasks/MpsCheck : org/gradle/api/tasks/JavaExec, de/itemis/mps/gradle/tasks/MpsProjectTask, org/gradle/api/tasks/VerificationTask { public fun ()V public fun exec ()V - public final fun getAdditionalModelcheckBackendClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; + public abstract fun getAdditionalModelcheckBackendClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; protected final fun getCompiledClasses ()Lorg/gradle/api/file/FileTree; - public final fun getExcludeModels ()Lorg/gradle/api/provider/ListProperty; - public final fun getExcludeModules ()Lorg/gradle/api/provider/ListProperty; - public fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; - public final fun getJunitFile ()Lorg/gradle/api/file/RegularFileProperty; - public final fun getJunitFormat ()Lorg/gradle/api/provider/Property; - public fun getLogLevel ()Lorg/gradle/api/provider/Property; - public final fun getModels ()Lorg/gradle/api/provider/ListProperty; - public final fun getModules ()Lorg/gradle/api/provider/ListProperty; - public fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; - public fun getMpsVersion ()Lorg/gradle/api/provider/Property; - public final fun getParallel ()Lorg/gradle/api/provider/Property; - public fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; - public fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; + public abstract fun getExcludeModels ()Lorg/gradle/api/provider/ListProperty; + public abstract fun getExcludeModules ()Lorg/gradle/api/provider/ListProperty; + public abstract fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; + public abstract fun getJunitFile ()Lorg/gradle/api/file/RegularFileProperty; + public abstract fun getJunitFormat ()Lorg/gradle/api/provider/Property; + public abstract fun getLogLevel ()Lorg/gradle/api/provider/Property; + public abstract fun getModels ()Lorg/gradle/api/provider/ListProperty; + public abstract fun getModules ()Lorg/gradle/api/provider/ListProperty; + public abstract fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; + public abstract fun getMpsVersion ()Lorg/gradle/api/provider/Property; + public abstract fun getParallel ()Lorg/gradle/api/provider/Property; + public abstract fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; + public abstract fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; protected final fun getSources ()Lorg/gradle/api/file/FileTree; - public final fun getWarningAsError ()Lorg/gradle/api/provider/Property; + public abstract fun getWarningAsError ()Lorg/gradle/api/provider/Property; } public abstract class de/itemis/mps/gradle/tasks/MpsExecute : org/gradle/api/tasks/JavaExec, de/itemis/mps/gradle/tasks/MpsProjectTask { public fun ()V public fun exec ()V - public final fun getAdditionalExecuteBackendClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; + public abstract fun getAdditionalExecuteBackendClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; public abstract fun getClassName ()Lorg/gradle/api/provider/Property; public abstract fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; public abstract fun getLogLevel ()Lorg/gradle/api/provider/Property; @@ -132,42 +132,44 @@ public abstract class de/itemis/mps/gradle/tasks/MpsExecute : org/gradle/api/tas public abstract class de/itemis/mps/gradle/tasks/MpsGenerate : org/gradle/api/tasks/JavaExec, de/itemis/mps/gradle/tasks/MpsProjectTask { public fun ()V public fun exec ()V - public final fun getAdditionalGenerateBackendClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; + public abstract fun getAdditionalGenerateBackendClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; protected final fun getCompiledClasses ()Lorg/gradle/api/file/FileTree; - public final fun getEnvironmentKind ()Lorg/gradle/api/provider/Property; - public final fun getExcludeModels ()Lorg/gradle/api/provider/ListProperty; - public final fun getExcludeModules ()Lorg/gradle/api/provider/ListProperty; - public fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; - public fun getLogLevel ()Lorg/gradle/api/provider/Property; - public final fun getModels ()Lorg/gradle/api/provider/ListProperty; - public final fun getModules ()Lorg/gradle/api/provider/ListProperty; - public fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; - public fun getMpsVersion ()Lorg/gradle/api/provider/Property; - public final fun getParallelGenerationThreads ()Lorg/gradle/api/provider/Property; - public fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; - public fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; + public abstract fun getEnvironmentKind ()Lorg/gradle/api/provider/Property; + public abstract fun getExcludeModels ()Lorg/gradle/api/provider/ListProperty; + public abstract fun getExcludeModules ()Lorg/gradle/api/provider/ListProperty; + public abstract fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; + public abstract fun getLogLevel ()Lorg/gradle/api/provider/Property; + public abstract fun getModels ()Lorg/gradle/api/provider/ListProperty; + public abstract fun getModules ()Lorg/gradle/api/provider/ListProperty; + public abstract fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; + public abstract fun getMpsVersion ()Lorg/gradle/api/provider/Property; + public abstract fun getParallelGenerationThreads ()Lorg/gradle/api/provider/Property; + public abstract fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; + public abstract fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; protected final fun getSources ()Lorg/gradle/api/file/FileTree; - public final fun getStrictMode ()Lorg/gradle/api/provider/Property; + public abstract fun getStrictMode ()Lorg/gradle/api/provider/Property; } public abstract class de/itemis/mps/gradle/tasks/MpsMigrate : org/gradle/api/DefaultTask, de/itemis/mps/gradle/tasks/MpsProjectTask { - public fun (Lorg/gradle/api/model/ObjectFactory;Lorg/gradle/api/provider/ProviderFactory;)V + public fun ()V public final fun execute ()V protected final fun getAllProjectFiles ()Lorg/gradle/api/provider/Provider; - public final fun getAntJvmArgs ()Lorg/gradle/api/provider/ListProperty; + public abstract fun getAntJvmArgs ()Lorg/gradle/api/provider/ListProperty; protected abstract fun getExecOperations ()Lorg/gradle/process/ExecOperations; - public fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; - public final fun getHaltOnDependencyError ()Lorg/gradle/api/provider/Property; - public final fun getHaltOnPrecheckFailure ()Lorg/gradle/api/provider/Property; - public fun getJavaLauncher ()Lorg/gradle/api/provider/Property; - public final fun getJvmArgs ()Lorg/gradle/api/provider/ListProperty; - public fun getLogLevel ()Lorg/gradle/api/provider/Property; - public final fun getMaxHeapSize ()Lorg/gradle/api/provider/Property; - public fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; - public fun getMpsVersion ()Lorg/gradle/api/provider/Property; - public fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; - public fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; - public final fun getProjectLocations ()Lorg/gradle/api/file/ConfigurableFileCollection; + public abstract fun getFolderMacros ()Lorg/gradle/api/provider/MapProperty; + public abstract fun getHaltOnDependencyError ()Lorg/gradle/api/provider/Property; + public abstract fun getHaltOnPrecheckFailure ()Lorg/gradle/api/provider/Property; + public abstract fun getJavaLauncher ()Lorg/gradle/api/provider/Property; + public abstract fun getJvmArgs ()Lorg/gradle/api/provider/ListProperty; + public abstract fun getLogLevel ()Lorg/gradle/api/provider/Property; + public abstract fun getMaxHeapSize ()Lorg/gradle/api/provider/Property; + public abstract fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; + public abstract fun getMpsVersion ()Lorg/gradle/api/provider/Property; + protected abstract fun getObjectFactory ()Lorg/gradle/api/model/ObjectFactory; + public abstract fun getPluginRoots ()Lorg/gradle/api/file/ConfigurableFileCollection; + public abstract fun getProjectLocation ()Lorg/gradle/api/file/DirectoryProperty; + public abstract fun getProjectLocations ()Lorg/gradle/api/file/ConfigurableFileCollection; + protected abstract fun getProviderFactory ()Lorg/gradle/api/provider/ProviderFactory; } public abstract class de/itemis/mps/gradle/tasks/Remigrate : org/gradle/api/tasks/JavaExec, de/itemis/mps/gradle/tasks/MpsProjectTask { diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt index 2634452..5be23eb 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt @@ -31,14 +31,12 @@ abstract class RunAntScript : DefaultTask(), MpsTask { @get:Inject protected abstract val execOperations: ExecOperations - @get:Internal - abstract override val mpsHome: DirectoryProperty - - private val javaLauncherProperty: Property = project.objects.property(JavaLauncher::class.java) + @Internal + abstract override fun getMpsHome(): DirectoryProperty @Nested @Optional - override fun getJavaLauncher(): Property = javaLauncherProperty + abstract override fun getJavaLauncher(): Property /** * Whether to build incrementally. @@ -92,7 +90,7 @@ abstract class RunAntScript : DefaultTask(), MpsTask { val targets = if (incremental) { targets - "clean" } else { targets } val effectiveExecutable = executable - ?: getJavaLauncher().orNull?.executablePath?.asFile + ?: javaLauncher.orNull?.executablePath?.asFile ?: project.findProperty("itemis.mps.gradle.ant.defaultJavaExecutable") val effectiveClasspath: FileCollection? = scriptClasspath ?: if (mpsHome.isPresent) { diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt index 91a261f..fa92e29 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt @@ -15,61 +15,68 @@ import org.gradle.api.provider.ListProperty import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.* -import org.gradle.kotlin.dsl.* +import org.gradle.kotlin.dsl.newInstance import org.gradle.process.CommandLineArgumentProvider @CacheableTask @Incubating abstract class MpsCheck : JavaExec(), VerificationTask, MpsProjectTask { - @get:Input - override val logLevel: Property = objectFactory.property().convention(project.gradle.startParameter.logLevel) + @Input + abstract override fun getLogLevel(): Property - @get:Internal("covered by mpsVersion and classpath") - override val mpsHome: DirectoryProperty = objectFactory.directoryProperty() + @Internal("covered by mpsVersion and classpath") + abstract override fun getMpsHome(): DirectoryProperty - @get:Input - @get:Optional - override val mpsVersion: Property = objectFactory.property() - .convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) + @Input + @Optional + abstract override fun getMpsVersion(): Property - @get:Internal("covered by sources") - override val projectLocation: DirectoryProperty = - objectFactory.directoryProperty().convention(project.layout.projectDirectory) + @Internal("covered by sources") + abstract override fun getProjectLocation(): DirectoryProperty - @get:Classpath - override val pluginRoots: ConfigurableFileCollection = objectFactory.fileCollection() + @Classpath + abstract override fun getPluginRoots(): ConfigurableFileCollection - @get:Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") - override val folderMacros: MapProperty = objectFactory.mapProperty() + @Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") + abstract override fun getFolderMacros(): MapProperty @get:Input - val models: ListProperty = objectFactory.listProperty() + abstract val models: ListProperty @get:Input - val modules: ListProperty = objectFactory.listProperty() + abstract val modules: ListProperty @get:Input - val excludeModels: ListProperty = objectFactory.listProperty() + abstract val excludeModels: ListProperty @get:Input - val excludeModules: ListProperty = objectFactory.listProperty() + abstract val excludeModules: ListProperty @get:Input - val warningAsError: Property = objectFactory.property().convention(false) + abstract val warningAsError: Property @get:OutputFile - val junitFile: RegularFileProperty = objectFactory.fileProperty() - .convention(project.layout.buildDirectory.map { it.file("TEST-${this@MpsCheck.name}.xml") }) + abstract val junitFile: RegularFileProperty @get:Input - val junitFormat: Property = objectFactory.property().convention("module-and-model") + abstract val junitFormat: Property @get:Input - val parallel: Property = objectFactory.property().convention(false) + abstract val parallel: Property @get:Internal("covered by classpath") - val additionalModelcheckBackendClasspath: ConfigurableFileCollection = objectFactory.fileCollection() + abstract val additionalModelcheckBackendClasspath: ConfigurableFileCollection + + init { + logLevel.convention(project.gradle.startParameter.logLevel) + mpsVersion.convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) + projectLocation.convention(project.layout.projectDirectory) + warningAsError.convention(false) + junitFile.convention(project.layout.buildDirectory.map { it.file("TEST-${this@MpsCheck.name}.xml") }) + junitFormat.convention("module-and-model") + parallel.convention(false) + } @Suppress("unused") @get:InputFiles diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt index 23fc00c..3192b8f 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt @@ -20,24 +20,24 @@ import org.gradle.work.DisableCachingByDefault @Incubating abstract class MpsExecute : JavaExec(), MpsProjectTask { - @get:Input - abstract override val logLevel: Property + @Input + abstract override fun getLogLevel(): Property - @get:Internal("covered by mpsVersion and classpath") - abstract override val mpsHome: DirectoryProperty + @Internal("covered by mpsVersion and classpath") + abstract override fun getMpsHome(): DirectoryProperty - @get:Input - @get:Optional - abstract override val mpsVersion: Property + @Input + @Optional + abstract override fun getMpsVersion(): Property - @get:Internal("covered by sources") - abstract override val projectLocation: DirectoryProperty + @Internal("covered by sources") + abstract override fun getProjectLocation(): DirectoryProperty - @get:Classpath - abstract override val pluginRoots: ConfigurableFileCollection + @Classpath + abstract override fun getPluginRoots(): ConfigurableFileCollection - @get:Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") - abstract override val folderMacros: MapProperty + @Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") + abstract override fun getFolderMacros(): MapProperty @get:Internal abstract val module: Property @@ -52,7 +52,7 @@ abstract class MpsExecute : JavaExec(), MpsProjectTask { abstract val methodArguments: ListProperty @get:Internal - val additionalExecuteBackendClasspath: ConfigurableFileCollection = objectFactory.fileCollection() + abstract val additionalExecuteBackendClasspath: ConfigurableFileCollection init { logLevel.convention(project.gradle.startParameter.logLevel) diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt index d79b2f4..50cc5db 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt @@ -15,61 +15,64 @@ import org.gradle.api.provider.ListProperty import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.* -import org.gradle.kotlin.dsl.listProperty -import org.gradle.kotlin.dsl.mapProperty import org.gradle.kotlin.dsl.newInstance -import org.gradle.kotlin.dsl.property import org.gradle.process.CommandLineArgumentProvider @CacheableTask @Incubating abstract class MpsGenerate : JavaExec(), MpsProjectTask { - @get:Input - override val logLevel: Property = objectFactory.property().convention(project.gradle.startParameter.logLevel) + @Input + abstract override fun getLogLevel(): Property - @get:Internal("covered by mpsVersion and classpath") - override val mpsHome: DirectoryProperty = objectFactory.directoryProperty() + @Internal("covered by mpsVersion and classpath") + abstract override fun getMpsHome(): DirectoryProperty - @get:Input - @get:Optional - override val mpsVersion: Property = objectFactory.property() - .convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) + @Input + @Optional + abstract override fun getMpsVersion(): Property - @get:Internal("covered by sources") - override val projectLocation: DirectoryProperty = - objectFactory.directoryProperty().convention(project.layout.projectDirectory) + @Internal("covered by sources") + abstract override fun getProjectLocation(): DirectoryProperty - @get:Classpath - override val pluginRoots: ConfigurableFileCollection = objectFactory.fileCollection() + @Classpath + abstract override fun getPluginRoots(): ConfigurableFileCollection - @get:Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") - override val folderMacros: MapProperty = objectFactory.mapProperty() + @Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") + abstract override fun getFolderMacros(): MapProperty @get:Input - val environmentKind: Property = objectFactory.property() - .convention(EnvironmentKind.MPS) + abstract val environmentKind: Property @get:Input - val models: ListProperty = objectFactory.listProperty() + abstract val models: ListProperty @get:Input - val modules: ListProperty = objectFactory.listProperty() + abstract val modules: ListProperty @get:Input - val excludeModels: ListProperty = objectFactory.listProperty() + abstract val excludeModels: ListProperty @get:Input - val excludeModules: ListProperty = objectFactory.listProperty() + abstract val excludeModules: ListProperty @get:Input - val strictMode: Property = objectFactory.property().convention(true) + abstract val strictMode: Property @get:Input - val parallelGenerationThreads: Property = objectFactory.property().convention(0) + abstract val parallelGenerationThreads: Property @get:Internal("covered by classpath") - val additionalGenerateBackendClasspath: ConfigurableFileCollection = objectFactory.fileCollection() + abstract val additionalGenerateBackendClasspath: ConfigurableFileCollection + + init { + logLevel.convention(project.gradle.startParameter.logLevel) + mpsVersion.convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) + projectLocation.convention(project.layout.projectDirectory) + environmentKind.convention(EnvironmentKind.MPS) + strictMode.convention(true) + parallelGenerationThreads.convention(0) + } @Suppress("unused") @get:InputFiles diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt index 043650a..9a59f88 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt @@ -17,30 +17,23 @@ import org.gradle.api.provider.Property import org.gradle.api.provider.ProviderFactory import org.gradle.api.tasks.* import org.gradle.jvm.toolchain.JavaLauncher -import org.gradle.kotlin.dsl.listProperty -import org.gradle.kotlin.dsl.mapProperty -import org.gradle.kotlin.dsl.property import org.gradle.kotlin.dsl.withGroovyBuilder import org.gradle.process.ExecOperations import java.io.File import javax.inject.Inject @UntrackedTask(because = "Operates 'in place'") -abstract class MpsMigrate @Inject constructor( - private val objectFactory: ObjectFactory, - providerFactory: ProviderFactory -) : DefaultTask(), MpsProjectTask { +abstract class MpsMigrate : DefaultTask(), MpsProjectTask { - @get:Input - override val logLevel: Property = objectFactory.property().convention(project.gradle.startParameter.logLevel) + @Input + abstract override fun getLogLevel(): Property - @get:Internal("covered by mpsVersion and classpath") - override val mpsHome: DirectoryProperty = objectFactory.directoryProperty() + @Internal("covered by mpsVersion and classpath") + abstract override fun getMpsHome(): DirectoryProperty - @get:Input - @get:Optional - override val mpsVersion: Property = objectFactory.property() - .convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) + @Input + @Optional + abstract override fun getMpsVersion(): Property /** * (Since MPS 2021.1) Whether to halt if a pre-check has failed. Note that to ignore the check for migrated @@ -48,20 +41,20 @@ abstract class MpsMigrate @Inject constructor( */ @get:Input @get:Optional - val haltOnPrecheckFailure: Property = objectFactory.property() + abstract val haltOnPrecheckFailure: Property /** * (Since MPS 2021.3.4) Whether to halt when a non-migrated dependency is discovered. */ @get:Input @get:Optional - val haltOnDependencyError: Property = objectFactory.property() + abstract val haltOnDependencyError: Property - @get:Internal("covered by allProjectFiles") - override val projectLocation: DirectoryProperty = objectFactory.directoryProperty() + @Internal("covered by allProjectFiles") + abstract override fun getProjectLocation(): DirectoryProperty @get:Internal("covered by allProjectFiles") - val projectLocations: ConfigurableFileCollection = objectFactory.fileCollection() + abstract val projectLocations: ConfigurableFileCollection @get:InputFiles @get:IgnoreEmptyDirectories @@ -71,32 +64,38 @@ abstract class MpsMigrate @Inject constructor( effectiveProjectLocations().flatMap { objectFactory.fileTree().from(it) } } - private val javaLauncherProperty: Property = objectFactory.property() - @Nested @Optional - override fun getJavaLauncher(): Property = javaLauncherProperty + abstract override fun getJavaLauncher(): Property @get:Input - val jvmArgs: ListProperty = objectFactory.listProperty() + abstract val jvmArgs: ListProperty @get:Input - val antJvmArgs: ListProperty = objectFactory.listProperty() + abstract val antJvmArgs: ListProperty @get:Input @get:Optional - val maxHeapSize: Property = objectFactory.property() + abstract val maxHeapSize: Property - @get:Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") - override val folderMacros: MapProperty = objectFactory.mapProperty() + @Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") + abstract override fun getFolderMacros(): MapProperty - @get:Classpath - override val pluginRoots: ConfigurableFileCollection = objectFactory.fileCollection() + @Classpath + abstract override fun getPluginRoots(): ConfigurableFileCollection @get:Inject protected abstract val execOperations: ExecOperations + @get:Inject + protected abstract val objectFactory: ObjectFactory + + @get:Inject + protected abstract val providerFactory: ProviderFactory + init { + logLevel.convention(project.gradle.startParameter.logLevel) + mpsVersion.convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) group = TaskGroups.MIGRATION } @@ -136,7 +135,7 @@ abstract class MpsMigrate @Inject constructor( mainClass.set("org.apache.tools.ant.launch.Launcher") workingDir = temporaryDir classpath = mpsAntClasspath - val executableCandidate = getJavaLauncher().orNull?.executablePath?.asFile?.toString() + val executableCandidate = javaLauncher.orNull?.executablePath?.asFile?.toString() if (executableCandidate != null) { executable = executableCandidate } diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt index 7bdc7dd..c0b32e9 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt @@ -22,18 +22,18 @@ import org.gradle.process.CommandLineArgumentProvider @UntrackedTask(because = "Operates 'in place'") abstract class Remigrate : JavaExec(), MpsProjectTask { - @get:Input - abstract override val logLevel: Property + @Input + abstract override fun getLogLevel(): Property - @get:Internal("covered by mpsVersion and classpath") - abstract override val mpsHome: DirectoryProperty + @Internal("covered by mpsVersion and classpath") + abstract override fun getMpsHome(): DirectoryProperty - @get:Input - @get:Optional - abstract override val mpsVersion: Property + @Input + @Optional + abstract override fun getMpsVersion(): Property - @get:Internal("covered by allProjectFiles") - abstract override val projectLocation: DirectoryProperty + @Internal("covered by allProjectFiles") + abstract override fun getProjectLocation(): DirectoryProperty @get:Internal("covered by allProjectFiles") abstract val projectLocations: ConfigurableFileCollection @@ -46,11 +46,11 @@ abstract class Remigrate : JavaExec(), MpsProjectTask { effectiveProjectLocations().flatMap { objectFactory.fileTree().from(it) } } - @get:Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") - abstract override val folderMacros: MapProperty + @Internal("Folder macros are ignored for the purposes of up-to-date checks and caching") + abstract override fun getFolderMacros(): MapProperty - @get:Classpath - abstract override val pluginRoots: ConfigurableFileCollection + @Classpath + abstract override fun getPluginRoots(): ConfigurableFileCollection @get:Internal abstract val additionalClasspath: ConfigurableFileCollection From f466326acda2887d89b7b421e0310de7320c94dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Wed, 22 Apr 2026 22:13:03 +0200 Subject: [PATCH 35/44] build: only run on Java 17 but provision 21 for migration tests There isn't much reason left to run the build on several JDKs since the JDK only affects what Gradle uses. The tasks use the appropriate JBR for the current MPS version. Also update the versions of used GitHub actions. --- .github/workflows/gradle.yml | 21 ++++++++++--------- .../src/test/kotlin/support/TestVersions.kt | 5 +++++ .../test/migration/RunMigrationsTest.kt | 10 +++++++++ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index b0088f2..69d04de 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -19,30 +19,31 @@ concurrency: jobs: build: - name: Build (JDK ${{ matrix.java }}) + name: Build runs-on: ubuntu-latest permissions: contents: read - strategy: - matrix: - java: [ 17, 21 ] steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v3 + - uses: actions/checkout@v6 + + # Set up Java to run Gradle. Gradle will then download the appropriate version(s) to compile the projects or run + # tests. + - uses: actions/setup-java@v5 with: distribution: temurin - java-version: ${{ matrix.java }} - - uses: gradle/actions/setup-gradle@v3 + java-version: 17 + + - uses: gradle/actions/setup-gradle@v6 - name: Build with Gradle run: ./gradlew build - name: Upload JUnit XMLs - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: failure() with: name: junit-xmls path: '**/build/test-results/**/TEST-*.xml' retention-days: 7 - - uses: mikepenz/action-junit-report@v5 + - uses: mikepenz/action-junit-report@v6 if: success() || failure() with: report_paths: '**/build/test-results/**/TEST-*.xml' diff --git a/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt b/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt index 857196e..030f2ec 100644 --- a/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt +++ b/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt @@ -6,6 +6,11 @@ package support */ const val MPS_VERSION = "2025.1.2" +/** + * The Java version to be used for [MPS_VERSION]. Updated manually. + */ +const val JAVA_VERSION_FOR_MPS = 21 + /** * Version of the foojay-resolver-convention plugin applied in the settings scripts that tests generate. * Kept in a single place so Renovate can bump it. diff --git a/mps-gradle-plugin/src/test/kotlin/test/migration/RunMigrationsTest.kt b/mps-gradle-plugin/src/test/kotlin/test/migration/RunMigrationsTest.kt index daf6beb..f1b9860 100644 --- a/mps-gradle-plugin/src/test/kotlin/test/migration/RunMigrationsTest.kt +++ b/mps-gradle-plugin/src/test/kotlin/test/migration/RunMigrationsTest.kt @@ -7,6 +7,8 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +import support.FOOJAY_RESOLVER_CONVENTION_VERSION +import support.JAVA_VERSION_FOR_MPS import support.MPS_VERSION import support.extractTestProject import java.io.File @@ -24,6 +26,9 @@ class RunMigrationsTest { settingsFile = testProjectDir.newFile("settings.gradle.kts") settingsFile.writeText( """ + plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version ("$FOOJAY_RESOLVER_CONVENTION_VERSION") + } rootProject.name = "hello-world" """.trimIndent() ) @@ -40,6 +45,7 @@ class RunMigrationsTest { plugins { id("de.itemis.mps.gradle.common") + `jvm-toolchains` } repositories { @@ -60,6 +66,10 @@ class RunMigrationsTest { val migrate by tasks.registering(MpsMigrate::class) { projectLocations.from("$mpsTestPrjLocation") mpsHome = layout.dir(resolveMps.map { it.destinationDir }) + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(${JAVA_VERSION_FOR_MPS}) + vendor = JvmVendorSpec.JETBRAINS + } } """.trimIndent() ) From 0335cef8ec1996579a2fce6d93af86204da03131 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 19:42:05 +0000 Subject: [PATCH 36/44] Update dependency org.gradle.toolchains.foojay-resolver-convention to v1 --- mps-gradle-plugin-api/settings.gradle.kts | 2 +- mps-gradle-plugin/settings.gradle.kts | 2 +- mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt | 2 +- settings.gradle.kts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mps-gradle-plugin-api/settings.gradle.kts b/mps-gradle-plugin-api/settings.gradle.kts index 70ebd33..4edc5e0 100644 --- a/mps-gradle-plugin-api/settings.gradle.kts +++ b/mps-gradle-plugin-api/settings.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version ("0.8.0") + id("org.gradle.toolchains.foojay-resolver-convention") version ("1.0.0") } dependencyResolutionManagement { diff --git a/mps-gradle-plugin/settings.gradle.kts b/mps-gradle-plugin/settings.gradle.kts index 325a9d8..4bed93f 100644 --- a/mps-gradle-plugin/settings.gradle.kts +++ b/mps-gradle-plugin/settings.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version ("0.8.0") + id("org.gradle.toolchains.foojay-resolver-convention") version ("1.0.0") } dependencyResolutionManagement { diff --git a/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt b/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt index 030f2ec..4049780 100644 --- a/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt +++ b/mps-gradle-plugin/src/test/kotlin/support/TestVersions.kt @@ -15,4 +15,4 @@ const val JAVA_VERSION_FOR_MPS = 21 * Version of the foojay-resolver-convention plugin applied in the settings scripts that tests generate. * Kept in a single place so Renovate can bump it. */ -const val FOOJAY_RESOLVER_CONVENTION_VERSION = "0.7.0" +const val FOOJAY_RESOLVER_CONVENTION_VERSION = "1.0.0" diff --git a/settings.gradle.kts b/settings.gradle.kts index 564035e..360ec4b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,7 +3,7 @@ pluginManagement { } plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version ("0.8.0") + id("org.gradle.toolchains.foojay-resolver-convention") version ("1.0.0") } rootProject.name = "mps-gradle-plugin" From 1241745cb9c0f1a48cdd4dd3ff719b0548ab50dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Thu, 23 Apr 2026 17:04:09 +0200 Subject: [PATCH 37/44] Release mps-gradle-plugin-api 1.0.0 Drop the -SNAPSHOT suffix and add an initial CHANGELOG for the newly extracted mps-gradle-plugin-api module. Also fill in the remaining 3.0.0 changelog notes in mps-gradle-plugin (Gradle 9 / Java 17 bump, api published as a separate artifact). Co-Authored-By: Claude Opus 4.7 (1M context) --- mps-gradle-plugin-api/CHANGELOG.md | 14 ++++++++++++++ mps-gradle-plugin-api/build.gradle.kts | 2 +- mps-gradle-plugin/CHANGELOG.md | 4 +++- 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 mps-gradle-plugin-api/CHANGELOG.md diff --git a/mps-gradle-plugin-api/CHANGELOG.md b/mps-gradle-plugin-api/CHANGELOG.md new file mode 100644 index 0000000..612ba74 --- /dev/null +++ b/mps-gradle-plugin-api/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 1.0.0 + +Initial release, extracted from `mps-gradle-plugin`. + +### Added + +- `MpsTask` interface for any task that operates on an MPS installation. Provides `mpsHome`, `mpsVersion`, and + `javaLauncher` properties. +- `MpsProjectTask` interface (extends `MpsTask`) for tasks that operate on MPS projects. Provides `projectLocation`, + `pluginRoots`, `folderMacros`, and `logLevel` properties. diff --git a/mps-gradle-plugin-api/build.gradle.kts b/mps-gradle-plugin-api/build.gradle.kts index 8ded536..6f6a44a 100644 --- a/mps-gradle-plugin-api/build.gradle.kts +++ b/mps-gradle-plugin-api/build.gradle.kts @@ -5,7 +5,7 @@ plugins { group = "de.itemis.mps" -version = "1.0.0-SNAPSHOT" +version = "1.0.0" repositories { mavenCentral() diff --git a/mps-gradle-plugin/CHANGELOG.md b/mps-gradle-plugin/CHANGELOG.md index 79e635d..b248029 100644 --- a/mps-gradle-plugin/CHANGELOG.md +++ b/mps-gradle-plugin/CHANGELOG.md @@ -19,7 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `MpsTask` interface for any task that operates on an MPS installation. Provides `mpsHome`, `mpsVersion`, and - `javaLauncher` properties. Implemented by all MPS task types including `RunAntScript`. + `javaLauncher` properties. Implemented by all MPS task types including `RunAntScript`. Published separately in the + new `de.itemis.mps:mps-gradle-plugin-api` artifact. - `MpsProjectTask` interface (extends `MpsTask`) for tasks that operate on MPS projects. Provides `projectLocation`, `pluginRoots`, `folderMacros`, and `logLevel` properties. Implemented by `MpsGenerate`, `MpsCheck`, `MpsExecute`, `MpsMigrate`, and `Remigrate`. @@ -27,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- The plugin now requires Gradle 9 and Java 17 (previously Gradle 8 and Java 11). - `MpsCheck`, `MpsExecute`: `pluginRoots` changed from `SetProperty` to `ConfigurableFileCollection`. - `MpsCheck`, `MpsExecute`: `macros`/`varMacros` replaced with `folderMacros: MapProperty`. - `MpsMigrate`, `Remigrate`: `projectDirectories` renamed to `projectLocations`. From 04d02e2253ab02d0ec6d24a3feca7477a341aa70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Thu, 23 Apr 2026 17:34:12 +0200 Subject: [PATCH 38/44] Add README for mps-gradle-plugin-api, clarify jbr-toolchain replacement Point users at the specificlanguages jbr-toolchain Gradle plugin instead of implying a replacement task inside this plugin. Co-Authored-By: Claude Opus 4.7 (1M context) --- mps-gradle-plugin-api/README.md | 46 +++++++++++++++++++++++++++++++++ mps-gradle-plugin/CHANGELOG.md | 8 +++--- 2 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 mps-gradle-plugin-api/README.md diff --git a/mps-gradle-plugin-api/README.md b/mps-gradle-plugin-api/README.md new file mode 100644 index 0000000..0ff6f24 --- /dev/null +++ b/mps-gradle-plugin-api/README.md @@ -0,0 +1,46 @@ +# mps-gradle-plugin-api + +Task-type interfaces shared across the MPS task types provided by [`mps-gradle-plugin`](../mps-gradle-plugin). + +## Coordinates + +```kotlin +dependencies { + compileOnly("de.itemis.mps:mps-gradle-plugin-api:1.0.0") +} +``` + +Requires Java 17. + +## Interfaces + +### `MpsTask` + +Any task that operates on an MPS installation. Provides: + +- `mpsHome: DirectoryProperty` — the MPS installation directory. +- `mpsVersion: Property` — MPS version string (e.g. `2021.3.3`). + Auto-detected from `mpsHome` when not set explicitly. +- `javaLauncher: Property` — Java launcher used to run MPS. + +### `MpsProjectTask` + +Extends `MpsTask` for tasks that operate on one or more MPS projects. Provides: + +- `projectLocation: DirectoryProperty` +- `pluginRoots: ConfigurableFileCollection` +- `folderMacros: MapProperty` +- `logLevel: Property` + +## Bulk configuration + +Use `tasks.withType` to configure every MPS task at once, for example to share +an MPS home and plugin roots across the whole build: + +```kotlin +tasks.withType().configureEach { + mpsHome = layout.projectDirectory.dir("mps") + projectLocation = layout.projectDirectory.dir("my-mps-project") + pluginRoots.from(mpsHome.dir("plugins")) +} +``` diff --git a/mps-gradle-plugin/CHANGELOG.md b/mps-gradle-plugin/CHANGELOG.md index b248029..6979f01 100644 --- a/mps-gradle-plugin/CHANGELOG.md +++ b/mps-gradle-plugin/CHANGELOG.md @@ -6,13 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed -- Old plugins (`generate-models`, `modelcheck`, `run-migrations`, `download-jbr`) have been removed. Use the task types +- Old plugins `generate-models`, `modelcheck`, and `run-migrations` have been removed. Use the task types (`MpsGenerate`, `MpsCheck`, `MpsMigrate`, `Remigrate`) directly instead. +- `download-jbr` plugin, `DownloadJbrForPlatform` task, and the `downloadJBR` package have been removed. Use the + [`com.specificlanguages.jbr-toolchain`](https://plugins.gradle.org/plugin/com.specificlanguages.jbr-toolchain) + plugin to download the JetBrains Runtime. - `CreateDmg` and `BundleMacosJdk` tasks have been removed. Building macOS installers is no longer in scope for this plugin. -- `DownloadJbrForPlatform` task and the `downloadJBR` package have been removed. Use the - [jbr-toolchain plugin](https://github.com/specificlanguages/mps-gradle-plugin/tree/master/subprojects/jbr-toolchain) - if JetBrains Runtime is required. - `GetMpsInBrowser` task has been removed. It only opened the JetBrains download page in a browser and did not pull its weight. From 30d5dcce813f058884b195be2a40bde7a45630dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Thu, 23 Apr 2026 17:44:43 +0200 Subject: [PATCH 39/44] Move shared task properties from MpsProjectTask to MpsTask pluginRoots, folderMacros, and logLevel apply to all MPS tasks, not just project-scoped ones. Hoisting them onto MpsTask leaves MpsProjectTask as the narrow "also has a projectLocation" marker. Co-Authored-By: Claude Opus 4.7 (1M context) --- mps-gradle-plugin-api/README.md | 19 +++++++---- .../mps/gradle/tasks/MpsProjectTask.java | 32 ++---------------- .../de/itemis/mps/gradle/tasks/MpsTask.java | 33 +++++++++++++++++++ mps-gradle-plugin/CHANGELOG.md | 11 +++---- 4 files changed, 53 insertions(+), 42 deletions(-) diff --git a/mps-gradle-plugin-api/README.md b/mps-gradle-plugin-api/README.md index 0ff6f24..153b19e 100644 --- a/mps-gradle-plugin-api/README.md +++ b/mps-gradle-plugin-api/README.md @@ -22,15 +22,17 @@ Any task that operates on an MPS installation. Provides: - `mpsVersion: Property` — MPS version string (e.g. `2021.3.3`). Auto-detected from `mpsHome` when not set explicitly. - `javaLauncher: Property` — Java launcher used to run MPS. +- `pluginRoots: ConfigurableFileCollection` — root directories containing MPS + plugins to load. +- `folderMacros: MapProperty` — folder macros (path + variables) to pass to MPS. +- `logLevel: Property` — log level for the MPS backend process. ### `MpsProjectTask` -Extends `MpsTask` for tasks that operate on one or more MPS projects. Provides: +Extends `MpsTask` for tasks that operate on an MPS project. Adds: -- `projectLocation: DirectoryProperty` -- `pluginRoots: ConfigurableFileCollection` -- `folderMacros: MapProperty` -- `logLevel: Property` +- `projectLocation: DirectoryProperty` — the MPS project directory. ## Bulk configuration @@ -38,9 +40,12 @@ Use `tasks.withType` to configure every MPS task at once, for example to share an MPS home and plugin roots across the whole build: ```kotlin -tasks.withType().configureEach { +tasks.withType().configureEach { mpsHome = layout.projectDirectory.dir("mps") - projectLocation = layout.projectDirectory.dir("my-mps-project") pluginRoots.from(mpsHome.dir("plugins")) } + +tasks.withType().configureEach { + projectLocation = layout.projectDirectory.dir("my-mps-project") +} ``` diff --git a/mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsProjectTask.java b/mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsProjectTask.java index 79ae473..71494f6 100644 --- a/mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsProjectTask.java +++ b/mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsProjectTask.java @@ -1,26 +1,18 @@ package de.itemis.mps.gradle.tasks; import org.gradle.api.Incubating; -import org.gradle.api.file.ConfigurableFileCollection; -import org.gradle.api.file.Directory; import org.gradle.api.file.DirectoryProperty; -import org.gradle.api.logging.LogLevel; -import org.gradle.api.provider.MapProperty; -import org.gradle.api.provider.Property; -import org.gradle.api.tasks.Classpath; -import org.gradle.api.tasks.Console; import org.gradle.api.tasks.Internal; /** - * A Gradle task that operates on one or more MPS projects. + * A Gradle task that operates on an MPS project. * - *

Use {@link org.gradle.api.tasks.TaskCollection#withType(Class)} to configure all MPS project tasks at once: + *

Adds {@link #getProjectLocation()} to the properties inherited from {@link MpsTask}. Use + * {@link org.gradle.api.tasks.TaskCollection#withType(Class)} to configure all MPS project tasks at once: * *

{@code
  * tasks.withType(MpsProjectTask.class).configureEach(task -> {
- *     task.getMpsHome().set(layout.getProjectDirectory().dir("mps"));
  *     task.getProjectLocation().set(layout.getProjectDirectory().dir("my-mps-project"));
- *     task.getPluginRoots().from(task.getMpsHome().dir("plugins"));
  * });
  * }
*/ @@ -33,22 +25,4 @@ public interface MpsProjectTask extends MpsTask { */ @Internal("too coarse to be used as input") DirectoryProperty getProjectLocation(); - - /** - * Root directories containing MPS plugins to load. - */ - @Classpath - ConfigurableFileCollection getPluginRoots(); - - /** - * Folder macros (path variables) to pass to MPS. Keys are macro names, values are directories. - */ - @Internal("not considered input") - MapProperty getFolderMacros(); - - /** - * Log level for the MPS backend process. - */ - @Console - Property getLogLevel(); } diff --git a/mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsTask.java b/mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsTask.java index 11c782e..7f138f0 100644 --- a/mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsTask.java +++ b/mps-gradle-plugin-api/src/main/java/de/itemis/mps/gradle/tasks/MpsTask.java @@ -2,8 +2,14 @@ import org.gradle.api.Incubating; import org.gradle.api.Task; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.Directory; import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.logging.LogLevel; +import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Classpath; +import org.gradle.api.tasks.Console; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.Nested; @@ -11,6 +17,15 @@ /** * A Gradle task that operates on an MPS installation. + * + *

Use {@link org.gradle.api.tasks.TaskCollection#withType(Class)} to configure all MPS tasks at once: + * + *

{@code
+ * tasks.withType(MpsTask.class).configureEach(task -> {
+ *     task.getMpsHome().set(layout.getProjectDirectory().dir("mps"));
+ *     task.getPluginRoots().from(task.getMpsHome().dir("plugins"));
+ * });
+ * }
*/ @Incubating public interface MpsTask extends Task { @@ -32,4 +47,22 @@ public interface MpsTask extends Task { */ @Nested Property getJavaLauncher(); + + /** + * Root directories containing MPS plugins to load. + */ + @Classpath + ConfigurableFileCollection getPluginRoots(); + + /** + * Folder macros (path variables) to pass to MPS. Keys are macro names, values are directories. + */ + @Internal("not considered input") + MapProperty getFolderMacros(); + + /** + * Log level for the MPS backend process. + */ + @Console + Property getLogLevel(); } diff --git a/mps-gradle-plugin/CHANGELOG.md b/mps-gradle-plugin/CHANGELOG.md index 6979f01..5ec37d6 100644 --- a/mps-gradle-plugin/CHANGELOG.md +++ b/mps-gradle-plugin/CHANGELOG.md @@ -18,12 +18,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- `MpsTask` interface for any task that operates on an MPS installation. Provides `mpsHome`, `mpsVersion`, and - `javaLauncher` properties. Implemented by all MPS task types including `RunAntScript`. Published separately in the - new `de.itemis.mps:mps-gradle-plugin-api` artifact. -- `MpsProjectTask` interface (extends `MpsTask`) for tasks that operate on MPS projects. Provides `projectLocation`, - `pluginRoots`, `folderMacros`, and `logLevel` properties. Implemented by `MpsGenerate`, `MpsCheck`, `MpsExecute`, - `MpsMigrate`, and `Remigrate`. +- `MpsTask` interface for any task that operates on an MPS installation. Provides `mpsHome`, `mpsVersion`, + `javaLauncher`, `pluginRoots`, `folderMacros`, and `logLevel` properties. Implemented by all MPS task types + including `RunAntScript`. Published separately in the new `de.itemis.mps:mps-gradle-plugin-api` artifact. +- `MpsProjectTask` interface (extends `MpsTask`) for tasks that operate on an MPS project. Adds `projectLocation`. + Implemented by `MpsGenerate`, `MpsCheck`, `MpsExecute`, `MpsMigrate`, and `Remigrate`. - Both interfaces allow bulk configuration via `tasks.withType()` and `tasks.withType()`. ### Changed From 0b54d979e06d23d38b99c411629fe3a8fb9381e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Thu, 23 Apr 2026 17:57:47 +0200 Subject: [PATCH 40/44] RunAntScript: use inherited logLevel and javaLauncher; require mpsHome - Drop the standalone executable property in favor of javaLauncher from MpsTask. The defaultJavaExecutable extended-property fallback is kept. - Use the inherited logLevel property to derive -Dmps.ant.log instead of task.logging.level. - Assume mpsHome is always present; mpsHome.get() will surface a clear Gradle error if a consumer forgets to set it. Centralize the MpsTask.logLevel convention in the common plugin via tasks.withType(), and remove the duplicated convention from each task's init block. Co-Authored-By: Claude Opus 4.7 (1M context) --- mps-gradle-plugin/CHANGELOG.md | 8 +++- mps-gradle-plugin/api/mps-gradle-plugin.api | 4 -- mps-gradle-plugin/docs/tasks/RunAntScript.md | 13 +++--- .../de/itemis/mps/gradle/RunAntScript.kt | 46 ++++++------------- .../de/itemis/mps/gradle/common.gradle.kts | 6 +++ .../de/itemis/mps/gradle/tasks/MpsCheck.kt | 1 - .../de/itemis/mps/gradle/tasks/MpsExecute.kt | 1 - .../de/itemis/mps/gradle/tasks/MpsGenerate.kt | 1 - .../de/itemis/mps/gradle/tasks/MpsMigrate.kt | 1 - .../de/itemis/mps/gradle/tasks/Remigrate.kt | 1 - 10 files changed, 32 insertions(+), 50 deletions(-) diff --git a/mps-gradle-plugin/CHANGELOG.md b/mps-gradle-plugin/CHANGELOG.md index 5ec37d6..8d2afd9 100644 --- a/mps-gradle-plugin/CHANGELOG.md +++ b/mps-gradle-plugin/CHANGELOG.md @@ -32,8 +32,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `MpsCheck`, `MpsExecute`: `macros`/`varMacros` replaced with `folderMacros: MapProperty`. - `MpsMigrate`, `Remigrate`: `projectDirectories` renamed to `projectLocations`. - `MpsMigrate`: `javaExecutable` removed in favor of `javaLauncher` from `MpsTask`. -- `RunAntScript`: derives Ant classpath from `mpsHome` when `scriptClasspath` is not set. Passes `mps.home` and - `mps_home` as Ant properties. +- `RunAntScript`: now requires `mpsHome`. Derives the Ant classpath from `mpsHome` when `scriptClasspath` is not set, + and passes `mps.home` and `mps_home` as Ant properties. +- `RunAntScript`: uses the inherited `javaLauncher` and `logLevel` properties. The `executable` property has been + removed (use `javaLauncher` instead); `-Dmps.ant.log` is derived from `logLevel` rather than from `task.logging.level`. +- The `de.itemis.mps.gradle.common` plugin sets the convention for `MpsTask.logLevel` to Gradle's + `gradle.startParameter.logLevel`, so MPS subprocesses log at the same level as Gradle by default. ## 1.30.1 diff --git a/mps-gradle-plugin/api/mps-gradle-plugin.api b/mps-gradle-plugin/api/mps-gradle-plugin.api index 561a21c..6d8564a 100644 --- a/mps-gradle-plugin/api/mps-gradle-plugin.api +++ b/mps-gradle-plugin/api/mps-gradle-plugin.api @@ -51,19 +51,15 @@ public abstract class de/itemis/mps/gradle/RunAntScript : org/gradle/api/Default public field script Ljava/lang/Object; public fun ()V public final fun build ()V - public final fun executable (Ljava/lang/Object;)V protected abstract fun getExecOperations ()Lorg/gradle/process/ExecOperations; - public final fun getExecutable ()Ljava/lang/Object; public final fun getIncludeDefaultArgs ()Z public final fun getIncludeDefaultClasspath ()Z public final fun getIncremental ()Z public abstract fun getJavaLauncher ()Lorg/gradle/api/provider/Property; - public abstract fun getMpsHome ()Lorg/gradle/api/file/DirectoryProperty; public final fun getScript ()Ljava/lang/Object; public final fun getScriptArgs ()Ljava/util/List; public final fun getScriptClasspath ()Lorg/gradle/api/file/FileCollection; public final fun getTargets ()Ljava/util/List; - public final fun setExecutable (Ljava/lang/Object;)V public final fun setIncludeDefaultArgs (Z)V public final fun setIncludeDefaultClasspath (Z)V public final fun setIncremental (Z)V diff --git a/mps-gradle-plugin/docs/tasks/RunAntScript.md b/mps-gradle-plugin/docs/tasks/RunAntScript.md index 8b37bf6..05e525c 100644 --- a/mps-gradle-plugin/docs/tasks/RunAntScript.md +++ b/mps-gradle-plugin/docs/tasks/RunAntScript.md @@ -12,15 +12,14 @@ Parameters: - `script`: path to the ANT to execute. - `scriptClasspath`: classpath used for the JVM that will execute the generated ANT script. Needs to contain ANT to be - able to run the build script. If not set and `mpsHome` is set, the classpath is derived from the MPS installation. - See below section "Providing Global Defaults" for project wide defaults. + able to run the build script. If not set, the classpath is derived from `mpsHome`. See below section + "Providing Global Defaults" for project wide defaults. - `scriptArgs`: additional command line arguments provided to the JVM that will execute the generated ANT scripts. This is often used to provide property valued via `-Dprop=value`. See below section "Providing Global Defaults" for project wide defaults. -- `mpsHome`: the MPS installation directory. When set, `mps.home` and `mps_home` are passed as Ant properties +- `mpsHome`: the MPS installation directory. Required. `mps.home` and `mps_home` are passed as Ant properties automatically, and the Ant classpath is derived from the MPS installation if `scriptClasspath` is not set. -- `javaLauncher`: the Java launcher to use for running MPS. Takes precedence over `executable` and the global default. -- `executable`: the `java` executable to use. Optional. If `itemis.mps.gradle.ant.defaultJavaExecutable` extended - property is set, its value is used as the default value for the parameter. +- `javaLauncher`: the Java launcher used to run the Ant script. Optional; if not set, the + `itemis.mps.gradle.ant.defaultJavaExecutable` extended property is used as a fallback. - `includeDefaultArgs`: controls whether the project-wide default values for arguments are used. It's set to `true` by default. - `includeDefaultClasspath`: controls whether the project-wide default values for the classpath are used. @@ -53,7 +52,7 @@ ext["itemis.mps.gradle.ant.defaultScriptClasspath"] = buildScriptClasspath ### Providing Global Defaults For The Java Executable The `itemis.mps.gradle.ant.defaultJavaExecutable` property specifies the value to use as the underlying -`JavaExec.executable`. The `executable` parameter of each individual task takes precedence over the global default. +`JavaExec.executable`. The `javaLauncher` of each individual task takes precedence over the global default. ### Incremental Builds diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt index 5be23eb..b02e05a 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt @@ -2,7 +2,6 @@ package de.itemis.mps.gradle; import de.itemis.mps.gradle.tasks.MpsTask import org.gradle.api.DefaultTask -import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileCollection import org.gradle.api.logging.LogLevel import org.gradle.api.provider.Property @@ -26,14 +25,9 @@ abstract class RunAntScript : DefaultTask(), MpsTask { var includeDefaultArgs = true @Input var includeDefaultClasspath = true - @Optional @Input - var executable: Any? = null @get:Inject protected abstract val execOperations: ExecOperations - @Internal - abstract override fun getMpsHome(): DirectoryProperty - @Nested @Optional abstract override fun getJavaLauncher(): Property @@ -55,10 +49,6 @@ abstract class RunAntScript : DefaultTask(), MpsTask { this.targets = targets.toList() } - fun executable(executable: Any?) { - this.executable = executable - } - @TaskAction fun build() { val allArgs = scriptArgs.toMutableList() @@ -69,37 +59,31 @@ abstract class RunAntScript : DefaultTask(), MpsTask { } } - if (logging.level != null && logging.level != LogLevel.LIFECYCLE && !allArgs.any { it.startsWith("-Dmps.ant.log=") }) { - allArgs += "-Dmps.ant.log=${logging.level.toString().lowercase()}" + val level = logLevel.get() + if (level != LogLevel.LIFECYCLE && !allArgs.any { it.startsWith("-Dmps.ant.log=") }) { + allArgs += "-Dmps.ant.log=${level.toString().lowercase()}" } if (incremental) { allArgs += "-Dmps.generator.skipUnmodifiedModels=true" } - if (mpsHome.isPresent) { - val mpsHomePath = mpsHome.get().asFile.absolutePath - if (!allArgs.any { it.startsWith("-Dmps.home=") }) { - allArgs += "-Dmps.home=$mpsHomePath" - } - if (!allArgs.any { it.startsWith("-Dmps_home=") }) { - allArgs += "-Dmps_home=$mpsHomePath" - } + val mpsHomePath = mpsHome.get().asFile.absolutePath + if (!allArgs.any { it.startsWith("-Dmps.home=") }) { + allArgs += "-Dmps.home=$mpsHomePath" + } + if (!allArgs.any { it.startsWith("-Dmps_home=") }) { + allArgs += "-Dmps_home=$mpsHomePath" } val targets = if (incremental) { targets - "clean" } else { targets } - val effectiveExecutable = executable - ?: javaLauncher.orNull?.executablePath?.asFile + val effectiveExecutable = javaLauncher.orNull?.executablePath?.asFile ?: project.findProperty("itemis.mps.gradle.ant.defaultJavaExecutable") - val effectiveClasspath: FileCollection? = scriptClasspath ?: if (mpsHome.isPresent) { - mpsHome.asFileTree.matching { - include("lib/ant/lib/*.jar") - include("lib/*.jar") - } - } else { - null + val effectiveClasspath: FileCollection = scriptClasspath ?: mpsHome.asFileTree.matching { + include("lib/ant/lib/*.jar") + include("lib/*.jar") } execOperations.javaexec { @@ -117,9 +101,7 @@ abstract class RunAntScript : DefaultTask(), MpsTask { } } - if (effectiveClasspath != null) { - classpath(effectiveClasspath) - } + classpath(effectiveClasspath) args(allArgs + "-buildfile" + project.file(script).toString() + targets) } diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/common.gradle.kts b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/common.gradle.kts index d296f72..3f3a497 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/common.gradle.kts +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/common.gradle.kts @@ -1,10 +1,16 @@ package de.itemis.mps.gradle +import de.itemis.mps.gradle.tasks.MpsTask + /** * A side effect of this plugin is that it lets us use `plugins` block rather than `buildscript` to put the task classes * ([RunAntScript], [BuildLanguages], etc.) onto the classpath. */ +tasks.withType().configureEach { + logLevel.convention(gradle.startParameter.logLevel) +} + val modelcheckBackend = configurations.create(BackendConfigurations.MODELCHECK_BACKEND_CONFIGURATION_NAME) val generateBackend = configurations.create(BackendConfigurations.GENERATE_BACKEND_CONFIGURATION_NAME) val executeBackend = configurations.create(BackendConfigurations.EXECUTE_BACKEND_CONFIGURATION_NAME) diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt index fa92e29..31d7f36 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsCheck.kt @@ -69,7 +69,6 @@ abstract class MpsCheck : JavaExec(), VerificationTask, MpsProjectTask { abstract val additionalModelcheckBackendClasspath: ConfigurableFileCollection init { - logLevel.convention(project.gradle.startParameter.logLevel) mpsVersion.convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) projectLocation.convention(project.layout.projectDirectory) warningAsError.convention(false) diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt index 3192b8f..c33c1fc 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsExecute.kt @@ -55,7 +55,6 @@ abstract class MpsExecute : JavaExec(), MpsProjectTask { abstract val additionalExecuteBackendClasspath: ConfigurableFileCollection init { - logLevel.convention(project.gradle.startParameter.logLevel) mpsVersion.convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) projectLocation.convention(project.layout.projectDirectory) diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt index 50cc5db..aab07e0 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsGenerate.kt @@ -66,7 +66,6 @@ abstract class MpsGenerate : JavaExec(), MpsProjectTask { abstract val additionalGenerateBackendClasspath: ConfigurableFileCollection init { - logLevel.convention(project.gradle.startParameter.logLevel) mpsVersion.convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) projectLocation.convention(project.layout.projectDirectory) environmentKind.convention(EnvironmentKind.MPS) diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt index 9a59f88..fb75e65 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/MpsMigrate.kt @@ -94,7 +94,6 @@ abstract class MpsMigrate : DefaultTask(), MpsProjectTask { protected abstract val providerFactory: ProviderFactory init { - logLevel.convention(project.gradle.startParameter.logLevel) mpsVersion.convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) group = TaskGroups.MIGRATION } diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt index c0b32e9..f7d8edd 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/tasks/Remigrate.kt @@ -63,7 +63,6 @@ abstract class Remigrate : JavaExec(), MpsProjectTask { } init { - logLevel.convention(project.gradle.startParameter.logLevel) mpsVersion.convention(MpsVersionDetection.fromMpsHome(project.layout, providerFactory, mpsHome.asFile)) additionalClasspath.from(mpsHome.asFileTree.matching { include("lib/**/*.jar") }) From 4a5ff01d9564f2b6706410b044ae9ecebae2e5a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Thu, 23 Apr 2026 18:06:48 +0200 Subject: [PATCH 41/44] RunAntScript: convert to lazy properties; drop ext-property defaults - script, targets, scriptArgs, scriptClasspath, and incremental become Property/ListProperty/ConfigurableFileCollection. Users assign with set/from/addAll instead of direct field assignment. - scriptClasspath gets a convention pointing at mpsHome's lib jars, so the manual fallback chain in build() goes away. - Remove the itemis.mps.gradle.ant.defaultScriptArgs, itemis.mps.gradle.ant.defaultScriptClasspath, and itemis.mps.gradle.ant.defaultJavaExecutable extended-property escape hatches along with the includeDefaultArgs/includeDefaultClasspath flags. Project-wide defaults belong in tasks.withType configureEach. - Drop the targets(vararg) helper; targets.set(listOf(...)) does the same thing. Co-Authored-By: Claude Opus 4.7 (1M context) --- mps-gradle-plugin/CHANGELOG.md | 6 ++ mps-gradle-plugin/api/mps-gradle-plugin.api | 21 ++--- mps-gradle-plugin/docs/tasks/RunAntScript.md | 56 +++++------- .../de/itemis/mps/gradle/RunAntScript.kt | 85 ++++++++----------- 4 files changed, 64 insertions(+), 104 deletions(-) diff --git a/mps-gradle-plugin/CHANGELOG.md b/mps-gradle-plugin/CHANGELOG.md index 8d2afd9..cdde6c8 100644 --- a/mps-gradle-plugin/CHANGELOG.md +++ b/mps-gradle-plugin/CHANGELOG.md @@ -34,8 +34,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `MpsMigrate`: `javaExecutable` removed in favor of `javaLauncher` from `MpsTask`. - `RunAntScript`: now requires `mpsHome`. Derives the Ant classpath from `mpsHome` when `scriptClasspath` is not set, and passes `mps.home` and `mps_home` as Ant properties. +- `RunAntScript`: `scriptClasspath`, `scriptArgs`, `targets`, `incremental`, and `script` are now lazy Gradle + properties (`ConfigurableFileCollection`, `ListProperty`, `Property`, `Property`). Use + `set`/`from`/`addAll` rather than direct assignment. - `RunAntScript`: uses the inherited `javaLauncher` and `logLevel` properties. The `executable` property has been removed (use `javaLauncher` instead); `-Dmps.ant.log` is derived from `logLevel` rather than from `task.logging.level`. +- `RunAntScript`: removed the `includeDefaultArgs`, `includeDefaultClasspath`, `itemis.mps.gradle.ant.defaultScriptArgs`, + `itemis.mps.gradle.ant.defaultScriptClasspath`, and `itemis.mps.gradle.ant.defaultJavaExecutable` escape hatches. + Use `tasks.withType().configureEach { ... }` to share configuration across tasks. - The `de.itemis.mps.gradle.common` plugin sets the convention for `MpsTask.logLevel` to Gradle's `gradle.startParameter.logLevel`, so MPS subprocesses log at the same level as Gradle by default. diff --git a/mps-gradle-plugin/api/mps-gradle-plugin.api b/mps-gradle-plugin/api/mps-gradle-plugin.api index 6d8564a..b71ec3a 100644 --- a/mps-gradle-plugin/api/mps-gradle-plugin.api +++ b/mps-gradle-plugin/api/mps-gradle-plugin.api @@ -48,26 +48,15 @@ public class de/itemis/mps/gradle/Pom : groovy/lang/GroovyObject { } public abstract class de/itemis/mps/gradle/RunAntScript : org/gradle/api/DefaultTask, de/itemis/mps/gradle/tasks/MpsTask { - public field script Ljava/lang/Object; public fun ()V public final fun build ()V protected abstract fun getExecOperations ()Lorg/gradle/process/ExecOperations; - public final fun getIncludeDefaultArgs ()Z - public final fun getIncludeDefaultClasspath ()Z - public final fun getIncremental ()Z + public abstract fun getIncremental ()Lorg/gradle/api/provider/Property; public abstract fun getJavaLauncher ()Lorg/gradle/api/provider/Property; - public final fun getScript ()Ljava/lang/Object; - public final fun getScriptArgs ()Ljava/util/List; - public final fun getScriptClasspath ()Lorg/gradle/api/file/FileCollection; - public final fun getTargets ()Ljava/util/List; - public final fun setIncludeDefaultArgs (Z)V - public final fun setIncludeDefaultClasspath (Z)V - public final fun setIncremental (Z)V - public final fun setScript (Ljava/lang/Object;)V - public final fun setScriptArgs (Ljava/util/List;)V - public final fun setScriptClasspath (Lorg/gradle/api/file/FileCollection;)V - public final fun setTargets (Ljava/util/List;)V - public final fun targets ([Ljava/lang/String;)V + public abstract fun getScript ()Lorg/gradle/api/provider/Property; + public abstract fun getScriptArgs ()Lorg/gradle/api/provider/ListProperty; + public abstract fun getScriptClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; + public abstract fun getTargets ()Lorg/gradle/api/provider/ListProperty; } public abstract class de/itemis/mps/gradle/TestLanguages : de/itemis/mps/gradle/RunAntScript { diff --git a/mps-gradle-plugin/docs/tasks/RunAntScript.md b/mps-gradle-plugin/docs/tasks/RunAntScript.md index 05e525c..a3c4454 100644 --- a/mps-gradle-plugin/docs/tasks/RunAntScript.md +++ b/mps-gradle-plugin/docs/tasks/RunAntScript.md @@ -8,52 +8,34 @@ because they may not exist yet when the build is started. ### Usage -Parameters: +Properties: -- `script`: path to the ANT to execute. -- `scriptClasspath`: classpath used for the JVM that will execute the generated ANT script. Needs to contain ANT to be - able to run the build script. If not set, the classpath is derived from `mpsHome`. See below section - "Providing Global Defaults" for project wide defaults. -- `scriptArgs`: additional command line arguments provided to the JVM that will execute the generated ANT scripts. This - is often used to provide property valued via `-Dprop=value`. See below section "Providing Global Defaults" for project wide defaults. +- `script`: path to the Ant script to execute. +- `scriptClasspath`: classpath used for the JVM that will execute the generated Ant script. Needs to contain Ant to be + able to run the build script. Defaults to `lib/ant/lib/*.jar` and `lib/*.jar` under `mpsHome`. +- `scriptArgs`: additional command line arguments provided to the JVM that will execute the generated Ant scripts. This + is often used to provide property valued via `-Dprop=value`. - `mpsHome`: the MPS installation directory. Required. `mps.home` and `mps_home` are passed as Ant properties automatically, and the Ant classpath is derived from the MPS installation if `scriptClasspath` is not set. -- `javaLauncher`: the Java launcher used to run the Ant script. Optional; if not set, the - `itemis.mps.gradle.ant.defaultJavaExecutable` extended property is used as a fallback. -- `includeDefaultArgs`: controls whether the project-wide default values for arguments are used. - It's set to `true` by default. -- `includeDefaultClasspath`: controls whether the project-wide default values for the classpath are used. - It's set to `true` by default. -- `targets`: the targets to execute of the ANT files. +- `javaLauncher`: the Java launcher used to run the Ant script. Optional. +- `targets`: the targets to execute of the Ant files. - `incremental`: enable incremental build, see below. (Since 1.6.) -### Providing Global Defaults For Class Path And Arguments +### Project-Wide Defaults -All tasks derived from the `RunAntScript` base class allow to specify default values for the classpath and script arguments -via project properties. By default, these values are added to the value specified for the parameters `scriptArgs` and -`scriptClasspath` if they are present. To opt out from the defaults see above the parameters `includeDefaultArgs` and -`includeDefaultClasspath`. +To share configuration across all `RunAntScript` tasks (and its subclasses), use Gradle's standard +`tasks.withType` mechanism: -The property `itemis.mps.gradle.ant.defaultScriptArgs` controls the default arguments provided to the build scripts -execution. In belows example the default arguments contain the version and build date. At runtime the default arguments -are combined with the arguments defined via `scriptArgs`. - -The property `itemis.mps.gradle.ant.defaultScriptClasspath` controls the default classpath provided to the build scripts -execution. In belows example the classpath contains ANT (via dependency configuration) and the tools jar from the JDK. -At runtime the default classpath are combined with the classpath defined via `scriptClasspath`. -``` -def defaultScriptArgs = ["-Dversion=$version", "-DbuildDate=${new Date().toString()}"] -def buildScriptClasspath = project.configurations.ant_lib.fileCollection({true}) + project.files("$project.jdk_home/lib/tools.jar") - -ext["itemis.mps.gradle.ant.defaultScriptArgs"] = defaultScriptArgs -ext["itemis.mps.gradle.ant.defaultScriptClasspath"] = buildScriptClasspath +```kotlin +tasks.withType().configureEach { + scriptArgs.addAll("-Dversion=$version", "-DbuildDate=${java.time.Instant.now()}") + scriptClasspath.from(configurations.named("antLib")) + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(17) + } +} ``` -### Providing Global Defaults For The Java Executable - -The `itemis.mps.gradle.ant.defaultJavaExecutable` property specifies the value to use as the underlying -`JavaExec.executable`. The `javaLauncher` of each individual task takes precedence over the global default. - ### Incremental Builds Incremental builds can be enabled by setting the `incremental` property to `true`. This has the following effects: diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt index b02e05a..1330ca3 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt @@ -2,8 +2,9 @@ package de.itemis.mps.gradle; import de.itemis.mps.gradle.tasks.MpsTask import org.gradle.api.DefaultTask -import org.gradle.api.file.FileCollection +import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.logging.LogLevel +import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.* import org.gradle.jvm.toolchain.JavaLauncher @@ -13,18 +14,18 @@ import javax.inject.Inject @DisableCachingByDefault(because = "Runs an Ant script that builds MPS languages and has non-trivial, external outputs") abstract class RunAntScript : DefaultTask(), MpsTask { - @Input - lateinit var script: Any - @Input - var targets: List = emptyList() - @Optional @Classpath - var scriptClasspath: FileCollection? = null - @Input - var scriptArgs: List = emptyList() - @Input - var includeDefaultArgs = true - @Input - var includeDefaultClasspath = true + @get:Input + abstract val script: Property + + @get:Input + abstract val targets: ListProperty + + @get:Classpath + abstract val scriptClasspath: ConfigurableFileCollection + + @get:Input + abstract val scriptArgs: ListProperty + @get:Inject protected abstract val execOperations: ExecOperations @@ -38,33 +39,32 @@ abstract class RunAntScript : DefaultTask(), MpsTask { * Possible values: * * `true` - perform an incremental build. If the [targets] list includes `clean` target it will be removed, and * `-Dmps.generator.skipUnmodifiedModels=true` will be passed to Ant. - * * `false` - The backwards compatible default. The [targets] list will not be modified and no properties will be - * passed to Ant. Any outside customizations made to targets and Ant arguments are left intact so the build may - * in fact be incremental. + * * `false` - the default. The [targets] list will not be modified and no properties will be passed to Ant. Any + * outside customizations made to targets and Ant arguments are left intact so the build may in fact be + * incremental. */ - @Input - var incremental: Boolean = false + @get:Input + abstract val incremental: Property - fun targets(vararg targets: String) { - this.targets = targets.toList() + init { + incremental.convention(false) + scriptClasspath.convention(mpsHome.asFileTree.matching { + include("lib/ant/lib/*.jar") + include("lib/*.jar") + }) } @TaskAction fun build() { - val allArgs = scriptArgs.toMutableList() - if (includeDefaultArgs) { - val defaultArgs = project.findProperty("itemis.mps.gradle.ant.defaultScriptArgs") as Collection<*>? - if (defaultArgs != null) { - allArgs += defaultArgs.map { it as String } - } - } + val allArgs = scriptArgs.get().toMutableList() val level = logLevel.get() if (level != LogLevel.LIFECYCLE && !allArgs.any { it.startsWith("-Dmps.ant.log=") }) { allArgs += "-Dmps.ant.log=${level.toString().lowercase()}" } - if (incremental) { + val isIncremental = incremental.get() + if (isIncremental) { allArgs += "-Dmps.generator.skipUnmodifiedModels=true" } @@ -76,34 +76,17 @@ abstract class RunAntScript : DefaultTask(), MpsTask { allArgs += "-Dmps_home=$mpsHomePath" } - val targets = if (incremental) { targets - "clean" } else { targets } - - val effectiveExecutable = javaLauncher.orNull?.executablePath?.asFile - ?: project.findProperty("itemis.mps.gradle.ant.defaultJavaExecutable") - - val effectiveClasspath: FileCollection = scriptClasspath ?: mpsHome.asFileTree.matching { - include("lib/ant/lib/*.jar") - include("lib/*.jar") - } + val effectiveTargets = targets.get().let { if (isIncremental) it - "clean" else it } execOperations.javaexec { - if (effectiveExecutable != null) { - executable(effectiveExecutable) - } + javaLauncher.orNull?.executablePath?.asFile?.let { executable(it) } mainClass.set("org.apache.tools.ant.launch.Launcher") workingDir = project.rootDir - if (includeDefaultClasspath) { - val defaultClasspath = project.findProperty("itemis.mps.gradle.ant.defaultScriptClasspath") - if (defaultClasspath != null) { - classpath(defaultClasspath) - } - } - - classpath(effectiveClasspath) + classpath(scriptClasspath) - args(allArgs + "-buildfile" + project.file(script).toString() + targets) + args(allArgs + "-buildfile" + project.file(script.get()).toString() + effectiveTargets) } } } @@ -111,13 +94,13 @@ abstract class RunAntScript : DefaultTask(), MpsTask { @DisableCachingByDefault(because = "Runs an Ant script that builds MPS languages and has non-trivial, external outputs") abstract class BuildLanguages : RunAntScript() { init { - targets = listOf("clean", "generate", "assemble") + targets.convention(listOf("clean", "generate", "assemble")) } } @DisableCachingByDefault(because = "Runs an Ant script that tests MPS languages and has non-trivial, external outputs") abstract class TestLanguages : RunAntScript() { init { - targets = listOf("clean", "generate", "assemble", "check") + targets.convention(listOf("clean", "generate", "assemble", "check")) } } From 4a1c1beb270ff745020903e78b4a99b7cf087143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Thu, 23 Apr 2026 19:06:28 +0200 Subject: [PATCH 42/44] RunAntScript: script as RegularFileProperty, extract workingDirectory - script becomes a RegularFileProperty annotated as @InputFile, so Gradle auto-wires dependencies from upstream tasks that generate it and tracks the script contents for up-to-date checks. - workingDirectory becomes a DirectoryProperty defaulting to the root project directory. The task action no longer touches project at execution time, playing nicer with the configuration cache. Co-Authored-By: Claude Opus 4.7 (1M context) --- mps-gradle-plugin/CHANGELOG.md | 7 ++++-- mps-gradle-plugin/api/mps-gradle-plugin.api | 3 ++- mps-gradle-plugin/docs/tasks/RunAntScript.md | 4 +++- .../de/itemis/mps/gradle/RunAntScript.kt | 23 ++++++++++++++----- .../test/kotlin/test/MpsTaskInterfaceTest.kt | 2 +- 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/mps-gradle-plugin/CHANGELOG.md b/mps-gradle-plugin/CHANGELOG.md index cdde6c8..b5ea346 100644 --- a/mps-gradle-plugin/CHANGELOG.md +++ b/mps-gradle-plugin/CHANGELOG.md @@ -35,8 +35,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `RunAntScript`: now requires `mpsHome`. Derives the Ant classpath from `mpsHome` when `scriptClasspath` is not set, and passes `mps.home` and `mps_home` as Ant properties. - `RunAntScript`: `scriptClasspath`, `scriptArgs`, `targets`, `incremental`, and `script` are now lazy Gradle - properties (`ConfigurableFileCollection`, `ListProperty`, `Property`, `Property`). Use - `set`/`from`/`addAll` rather than direct assignment. + properties (`ConfigurableFileCollection`, `ListProperty`, `Property`, `RegularFileProperty`). Use + `set`/`from`/`addAll` rather than direct assignment. `script` is tracked as a proper `@InputFile`, so wiring it via + `script.set(otherTask.flatMap { ... })` establishes the task dependency automatically. +- `RunAntScript`: added `workingDirectory: DirectoryProperty` (defaults to the root project directory) so the task + no longer reaches through `project` at execution time. - `RunAntScript`: uses the inherited `javaLauncher` and `logLevel` properties. The `executable` property has been removed (use `javaLauncher` instead); `-Dmps.ant.log` is derived from `logLevel` rather than from `task.logging.level`. - `RunAntScript`: removed the `includeDefaultArgs`, `includeDefaultClasspath`, `itemis.mps.gradle.ant.defaultScriptArgs`, diff --git a/mps-gradle-plugin/api/mps-gradle-plugin.api b/mps-gradle-plugin/api/mps-gradle-plugin.api index b71ec3a..94130d4 100644 --- a/mps-gradle-plugin/api/mps-gradle-plugin.api +++ b/mps-gradle-plugin/api/mps-gradle-plugin.api @@ -53,10 +53,11 @@ public abstract class de/itemis/mps/gradle/RunAntScript : org/gradle/api/Default protected abstract fun getExecOperations ()Lorg/gradle/process/ExecOperations; public abstract fun getIncremental ()Lorg/gradle/api/provider/Property; public abstract fun getJavaLauncher ()Lorg/gradle/api/provider/Property; - public abstract fun getScript ()Lorg/gradle/api/provider/Property; + public abstract fun getScript ()Lorg/gradle/api/file/RegularFileProperty; public abstract fun getScriptArgs ()Lorg/gradle/api/provider/ListProperty; public abstract fun getScriptClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; public abstract fun getTargets ()Lorg/gradle/api/provider/ListProperty; + public abstract fun getWorkingDirectory ()Lorg/gradle/api/file/DirectoryProperty; } public abstract class de/itemis/mps/gradle/TestLanguages : de/itemis/mps/gradle/RunAntScript { diff --git a/mps-gradle-plugin/docs/tasks/RunAntScript.md b/mps-gradle-plugin/docs/tasks/RunAntScript.md index a3c4454..0260418 100644 --- a/mps-gradle-plugin/docs/tasks/RunAntScript.md +++ b/mps-gradle-plugin/docs/tasks/RunAntScript.md @@ -10,7 +10,9 @@ because they may not exist yet when the build is started. Properties: -- `script`: path to the Ant script to execute. +- `script`: the Ant script to execute (`RegularFileProperty`). Wire via `script.set(otherTask.flatMap { ... })` to + depend on a task that generates the script. +- `workingDirectory`: working directory for the Ant invocation. Defaults to the root project directory. - `scriptClasspath`: classpath used for the JVM that will execute the generated Ant script. Needs to contain Ant to be able to run the build script. Defaults to `lib/ant/lib/*.jar` and `lib/*.jar` under `mpsHome`. - `scriptArgs`: additional command line arguments provided to the JVM that will execute the generated Ant scripts. This diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt index 1330ca3..69d61a9 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt @@ -3,6 +3,8 @@ package de.itemis.mps.gradle; import de.itemis.mps.gradle.tasks.MpsTask import org.gradle.api.DefaultTask import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty import org.gradle.api.logging.LogLevel import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property @@ -14,8 +16,9 @@ import javax.inject.Inject @DisableCachingByDefault(because = "Runs an Ant script that builds MPS languages and has non-trivial, external outputs") abstract class RunAntScript : DefaultTask(), MpsTask { - @get:Input - abstract val script: Property + @get:InputFile + @get:PathSensitive(PathSensitivity.NONE) + abstract val script: RegularFileProperty @get:Input abstract val targets: ListProperty @@ -26,6 +29,9 @@ abstract class RunAntScript : DefaultTask(), MpsTask { @get:Input abstract val scriptArgs: ListProperty + @get:Internal("working directory has no effect on the output") + abstract val workingDirectory: DirectoryProperty + @get:Inject protected abstract val execOperations: ExecOperations @@ -52,6 +58,7 @@ abstract class RunAntScript : DefaultTask(), MpsTask { include("lib/ant/lib/*.jar") include("lib/*.jar") }) + workingDirectory.convention(project.rootProject.layout.projectDirectory) } @TaskAction @@ -76,17 +83,21 @@ abstract class RunAntScript : DefaultTask(), MpsTask { allArgs += "-Dmps_home=$mpsHomePath" } - val effectiveTargets = targets.get().let { if (isIncremental) it - "clean" else it } + allArgs += "-buildfile" + allArgs += script.get().asFile.absolutePath + allArgs += targets.get().let { if (isIncremental) it - "clean" else it } execOperations.javaexec { - javaLauncher.orNull?.executablePath?.asFile?.let { executable(it) } + if (javaLauncher.isPresent) { + executable(javaLauncher.get().executablePath) + } mainClass.set("org.apache.tools.ant.launch.Launcher") - workingDir = project.rootDir + workingDir = workingDirectory.get().asFile classpath(scriptClasspath) - args(allArgs + "-buildfile" + project.file(script.get()).toString() + effectiveTargets) + args(allArgs) } } } diff --git a/mps-gradle-plugin/src/test/kotlin/test/MpsTaskInterfaceTest.kt b/mps-gradle-plugin/src/test/kotlin/test/MpsTaskInterfaceTest.kt index 9adfd4c..596070c 100644 --- a/mps-gradle-plugin/src/test/kotlin/test/MpsTaskInterfaceTest.kt +++ b/mps-gradle-plugin/src/test/kotlin/test/MpsTaskInterfaceTest.kt @@ -85,7 +85,7 @@ class MpsTaskInterfaceTest { val generate by tasks.registering(MpsGenerate::class) val buildLangs by tasks.registering(BuildLanguages::class) { - script = "build.xml" + script = layout.projectDirectory.file("build.xml") } tasks.withType().configureEach { From a149d5ab4e0e57eab99cd6d204fd0137c44e72e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Thu, 23 Apr 2026 19:55:05 +0200 Subject: [PATCH 43/44] RunAntScript: drop incremental build support The incremental flag muted the clean target and added -Dmps.generator.skipUnmodifiedModels=true. Consumers that need that behavior can configure scriptArgs and targets themselves. Co-Authored-By: Claude Opus 4.7 (1M context) --- mps-gradle-plugin/CHANGELOG.md | 2 ++ mps-gradle-plugin/api/mps-gradle-plugin.api | 1 - mps-gradle-plugin/docs/tasks/RunAntScript.md | 14 ------------- .../de/itemis/mps/gradle/RunAntScript.kt | 21 +------------------ 4 files changed, 3 insertions(+), 35 deletions(-) diff --git a/mps-gradle-plugin/CHANGELOG.md b/mps-gradle-plugin/CHANGELOG.md index b5ea346..6c1405d 100644 --- a/mps-gradle-plugin/CHANGELOG.md +++ b/mps-gradle-plugin/CHANGELOG.md @@ -45,6 +45,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `RunAntScript`: removed the `includeDefaultArgs`, `includeDefaultClasspath`, `itemis.mps.gradle.ant.defaultScriptArgs`, `itemis.mps.gradle.ant.defaultScriptClasspath`, and `itemis.mps.gradle.ant.defaultJavaExecutable` escape hatches. Use `tasks.withType().configureEach { ... }` to share configuration across tasks. +- `RunAntScript`: removed the `incremental` property. Pass `-Dmps.generator.skipUnmodifiedModels=true` via `scriptArgs` + and adjust `targets` directly if you need the previous behavior. - The `de.itemis.mps.gradle.common` plugin sets the convention for `MpsTask.logLevel` to Gradle's `gradle.startParameter.logLevel`, so MPS subprocesses log at the same level as Gradle by default. diff --git a/mps-gradle-plugin/api/mps-gradle-plugin.api b/mps-gradle-plugin/api/mps-gradle-plugin.api index 94130d4..9d8fde3 100644 --- a/mps-gradle-plugin/api/mps-gradle-plugin.api +++ b/mps-gradle-plugin/api/mps-gradle-plugin.api @@ -51,7 +51,6 @@ public abstract class de/itemis/mps/gradle/RunAntScript : org/gradle/api/Default public fun ()V public final fun build ()V protected abstract fun getExecOperations ()Lorg/gradle/process/ExecOperations; - public abstract fun getIncremental ()Lorg/gradle/api/provider/Property; public abstract fun getJavaLauncher ()Lorg/gradle/api/provider/Property; public abstract fun getScript ()Lorg/gradle/api/file/RegularFileProperty; public abstract fun getScriptArgs ()Lorg/gradle/api/provider/ListProperty; diff --git a/mps-gradle-plugin/docs/tasks/RunAntScript.md b/mps-gradle-plugin/docs/tasks/RunAntScript.md index 0260418..8a9a533 100644 --- a/mps-gradle-plugin/docs/tasks/RunAntScript.md +++ b/mps-gradle-plugin/docs/tasks/RunAntScript.md @@ -21,7 +21,6 @@ Properties: automatically, and the Ant classpath is derived from the MPS installation if `scriptClasspath` is not set. - `javaLauncher`: the Java launcher used to run the Ant script. Optional. - `targets`: the targets to execute of the Ant files. -- `incremental`: enable incremental build, see below. (Since 1.6.) ### Project-Wide Defaults @@ -38,16 +37,3 @@ tasks.withType().configureEach { } ``` -### Incremental Builds - -Incremental builds can be enabled by setting the `incremental` property to `true`. This has the following effects: -* The `clean` target is removed from the `targets` list. -* Argument `-Dmps.generator.skipUnmodifiedModels=true` is passed to Ant. This property tells the MPS generator to skip - generating and compiling models that have not been modified. - -NOTE: While incremental builds are convenient, it is necessary to be aware of their limitations. To determine whether -a model should be regenerated the generator only looks at the hash of the model contents. If the contents have not -changed since the last generation the generation is skipped. This may not be fully correct in the general case. Changing -the generator of a language used by the model may affect the generated code for the model, for example. Changes in -imported models may affect the generation output of this model as well. None of these changes would be detected via the -model contents hash. diff --git a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt index 69d61a9..891a7c7 100644 --- a/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt +++ b/mps-gradle-plugin/src/main/kotlin/de/itemis/mps/gradle/RunAntScript.kt @@ -39,21 +39,7 @@ abstract class RunAntScript : DefaultTask(), MpsTask { @Optional abstract override fun getJavaLauncher(): Property - /** - * Whether to build incrementally. - * - * Possible values: - * * `true` - perform an incremental build. If the [targets] list includes `clean` target it will be removed, and - * `-Dmps.generator.skipUnmodifiedModels=true` will be passed to Ant. - * * `false` - the default. The [targets] list will not be modified and no properties will be passed to Ant. Any - * outside customizations made to targets and Ant arguments are left intact so the build may in fact be - * incremental. - */ - @get:Input - abstract val incremental: Property - init { - incremental.convention(false) scriptClasspath.convention(mpsHome.asFileTree.matching { include("lib/ant/lib/*.jar") include("lib/*.jar") @@ -70,11 +56,6 @@ abstract class RunAntScript : DefaultTask(), MpsTask { allArgs += "-Dmps.ant.log=${level.toString().lowercase()}" } - val isIncremental = incremental.get() - if (isIncremental) { - allArgs += "-Dmps.generator.skipUnmodifiedModels=true" - } - val mpsHomePath = mpsHome.get().asFile.absolutePath if (!allArgs.any { it.startsWith("-Dmps.home=") }) { allArgs += "-Dmps.home=$mpsHomePath" @@ -85,7 +66,7 @@ abstract class RunAntScript : DefaultTask(), MpsTask { allArgs += "-buildfile" allArgs += script.get().asFile.absolutePath - allArgs += targets.get().let { if (isIncremental) it - "clean" else it } + allArgs += targets.get() execOperations.javaexec { if (javaLauncher.isPresent) { From 33113fe8a371c884ecdb6c2312e8cf6cb653ce0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergej=20Ko=C5=A1=C4=8Dejev?= Date: Thu, 23 Apr 2026 20:09:31 +0200 Subject: [PATCH 44/44] CHANGELOG: drop stale incremental mention from RunAntScript lazy-properties note Co-Authored-By: Claude Opus 4.7 (1M context) --- mps-gradle-plugin/CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mps-gradle-plugin/CHANGELOG.md b/mps-gradle-plugin/CHANGELOG.md index 6c1405d..346864a 100644 --- a/mps-gradle-plugin/CHANGELOG.md +++ b/mps-gradle-plugin/CHANGELOG.md @@ -34,9 +34,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `MpsMigrate`: `javaExecutable` removed in favor of `javaLauncher` from `MpsTask`. - `RunAntScript`: now requires `mpsHome`. Derives the Ant classpath from `mpsHome` when `scriptClasspath` is not set, and passes `mps.home` and `mps_home` as Ant properties. -- `RunAntScript`: `scriptClasspath`, `scriptArgs`, `targets`, `incremental`, and `script` are now lazy Gradle - properties (`ConfigurableFileCollection`, `ListProperty`, `Property`, `RegularFileProperty`). Use - `set`/`from`/`addAll` rather than direct assignment. `script` is tracked as a proper `@InputFile`, so wiring it via +- `RunAntScript`: `scriptClasspath`, `scriptArgs`, `targets`, and `script` are now lazy Gradle properties + (`ConfigurableFileCollection`, `ListProperty`, `RegularFileProperty`). Use `set`/`from`/`addAll` rather than + direct assignment. `script` is tracked as a proper `@InputFile`, so wiring it via `script.set(otherTask.flatMap { ... })` establishes the task dependency automatically. - `RunAntScript`: added `workingDirectory: DirectoryProperty` (defaults to the root project directory) so the task no longer reaches through `project` at execution time.