From ec4358b28024177567ab2d60eb636b2ca8af161c Mon Sep 17 00:00:00 2001 From: Stefan Oehme Date: Tue, 31 Aug 2021 15:51:02 +0200 Subject: [PATCH] Simplify xtextTooling dependency setup Create the xtextTooling Configuration for each SourceSet right away rather than lazily. This makes it visible in the output of the `dependencies` task and allows users to easily customize it in their build scripts, e.g. when there is another issue like https://github.com/xtext/xtext-gradle-plugin/issues/187 Use lazy callback APIs like `eachDependency` (to align versions for Xtext itself) and `withDependencies` (to add the BOM when that Xtext version has one) instead of using the Gradle-interna LazilyInitializedFileCollection. Load all dependencies, including the Xtext languages into the xtextTooling Configuration so that all version numbers are aligned. Previously it was possible for the xtextLanguages Configuration to bring in incompatible versions of libraries like eclipse.core.resources, which was especially visible when trying to use Xcore with this plugin. Now everything is aligned with the Xtext BOM and/or our dependency resolution rules. Remove the complicated "classpathInferrer" logic in favor of this new approach. This also means that the Xtend plugin is now much simpler, since it only needs to add the xtend.core dependency to the xtextTooling Configurations and that version will automatically be aligned by our resolution rules. This raises the minimum Gradle version to 4.7, which seems very reasonable given that the latest is 7.2. --- gradle.properties | 2 +- .../gradle/XtendLanguageBasePlugin.xtend | 24 +--- .../org/xtext/gradle/XtextBuilderPlugin.xtend | 109 ++++++++++-------- .../gradle/tasks/XtextClasspathInferrer.java | 8 -- .../xtext/gradle/tasks/XtextExtension.xtend | 30 ----- 5 files changed, 65 insertions(+), 108 deletions(-) delete mode 100644 xtext-gradle-plugin/src/main/java/org/xtext/gradle/tasks/XtextClasspathInferrer.java diff --git a/gradle.properties b/gradle.properties index 1a131eaf..48e59c05 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ minimumXtextVersion = 2.9.0 latestXtextVersion = 2.25.0 -minimumGradleVersion = 4.3 +minimumGradleVersion = 4.7 latestGradleVersion = 7.2 systemProp.http.connectionTimeout=120000 systemProp.http.socketTimeout=120000 diff --git a/xtext-gradle-plugin/src/main/java/org/xtext/gradle/XtendLanguageBasePlugin.xtend b/xtext-gradle-plugin/src/main/java/org/xtext/gradle/XtendLanguageBasePlugin.xtend index 1accf7fb..ec796209 100644 --- a/xtext-gradle-plugin/src/main/java/org/xtext/gradle/XtendLanguageBasePlugin.xtend +++ b/xtext-gradle-plugin/src/main/java/org/xtext/gradle/XtendLanguageBasePlugin.xtend @@ -1,16 +1,12 @@ package org.xtext.gradle -import org.gradle.api.GradleException import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.file.FileCollection import org.gradle.api.internal.plugins.DslObject import org.gradle.api.plugins.JavaBasePlugin import org.gradle.api.plugins.JavaPluginConvention import org.xtext.gradle.protocol.GradleInstallDebugInfoRequest.SourceInstaller -import org.xtext.gradle.tasks.XtextClasspathInferrer import org.xtext.gradle.tasks.XtextExtension -import org.xtext.gradle.tasks.XtextSourceDirectorySet import org.xtext.gradle.tasks.internal.XtendSourceSet class XtendLanguageBasePlugin implements Plugin { @@ -25,6 +21,9 @@ class XtendLanguageBasePlugin implements Plugin { plugin(XtextBuilderPlugin) ] xtext = project.extensions.getByType(XtextExtension) + xtext.sourceSets.all [ + project.dependencies.add(qualifyConfigurationName('xtextTooling'), 'org.eclipse.xtend:org.eclipse.xtend.core') + ] val xtend = xtext.languages.create("xtend") [ setup = "org.eclipse.xtend.core.XtendStandaloneSetup" generator.outlet => [ @@ -34,7 +33,6 @@ class XtendLanguageBasePlugin implements Plugin { sourceInstaller = SourceInstaller.SMAP ] ] - automaticallyInferXtendCompilerClasspath project.extensions.add("xtend", xtend) val java = project.convention.getPlugin(JavaPluginConvention) java.sourceSets.all [ sourceSet | @@ -45,20 +43,4 @@ class XtendLanguageBasePlugin implements Plugin { new DslObject(sourceSet).convention.plugins.put("xtend", xtendSourceSet) ] } - - private def void automaticallyInferXtendCompilerClasspath() { - xtext.classpathInferrers += new XtextClasspathInferrer() { - override inferXtextClasspath(XtextSourceDirectorySet sourceSet, FileCollection xtextClasspath, FileCollection classpath) { - val version = xtext.getXtextVersion(classpath) ?: xtext.getXtextVersion(xtextClasspath) - if (version === null) { - throw new GradleException('''Could not infer Xtext classpath, because xtext.version was not set and no xtext libraries were found on the «classpath» classpath''') - } - val xtendTooling = project.configurations.create(sourceSet.qualifyConfigurationName("xtendTooling")) - xtendTooling.dependencies += project.dependencies.create("org.eclipse.xtend:org.eclipse.xtend.core:" + version) - xtext.makeXtextCompatible(xtendTooling) - xtext.forceXtextVersion(xtendTooling, version) - xtendTooling.plus(xtextClasspath) - } - } - } } diff --git a/xtext-gradle-plugin/src/main/java/org/xtext/gradle/XtextBuilderPlugin.xtend b/xtext-gradle-plugin/src/main/java/org/xtext/gradle/XtextBuilderPlugin.xtend index 6376758e..c3bcf887 100644 --- a/xtext-gradle-plugin/src/main/java/org/xtext/gradle/XtextBuilderPlugin.xtend +++ b/xtext-gradle-plugin/src/main/java/org/xtext/gradle/XtextBuilderPlugin.xtend @@ -11,10 +11,7 @@ import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.artifacts.Configuration -import org.gradle.api.file.FileCollection -import org.gradle.api.internal.file.collections.LazilyInitializedFileCollection import org.gradle.api.internal.plugins.DslObject -import org.gradle.api.internal.tasks.TaskDependencyResolveContext import org.gradle.api.plugins.JavaBasePlugin import org.gradle.api.plugins.JavaPluginConvention import org.gradle.api.tasks.Delete @@ -22,7 +19,6 @@ import org.gradle.api.tasks.compile.JavaCompile import org.gradle.plugins.ide.eclipse.EclipsePlugin import org.gradle.plugins.ide.eclipse.model.EclipseModel import org.xtext.gradle.tasks.Outlet -import org.xtext.gradle.tasks.XtextClasspathInferrer import org.xtext.gradle.tasks.XtextEclipseSettings import org.xtext.gradle.tasks.XtextExtension import org.xtext.gradle.tasks.XtextGenerate @@ -46,8 +42,6 @@ class XtextBuilderPlugin implements Plugin { xtext = project.extensions.create("xtext", XtextExtension, project); xtextLanguages = project.configurations.create("xtextLanguages") - xtext.makeXtextCompatible(xtextLanguages) - automaticallyInferXtextCoreClasspath createGeneratorTasks configureOutletDefaults integrateWithJavaPlugin @@ -56,27 +50,12 @@ class XtextBuilderPlugin implements Plugin { private def createGeneratorTasks() { xtext.sourceSets.all [ sourceSet | - project.tasks.create(sourceSet.generatorTaskName, XtextGenerate) [ + val generatorTask = project.tasks.create(sourceSet.generatorTaskName, XtextGenerate) [ sources = sourceSet sourceSetOutputs = sourceSet.output languages = xtext.languages - val XtextGenerate generate = it - xtextClasspath = new LazilyInitializedFileCollection() { - override getDisplayName() { - "Xtext classpath" - } - - override createDelegate() { - inferXtextClasspath(sourceSet, generate.classpath) - } - - override visitDependencies(TaskDependencyResolveContext context) { - context.add(generate.classpath) - context.add(xtextLanguages) - } - - } ] + setupXtextClasspath(sourceSet, generatorTask) project.tasks.create('clean' + sourceSet.generatorTaskName.toFirstUpper, Delete) [ delete([ xtext.languages.map[generator.outlets].flatten.filter[cleanAutomatically].map [ @@ -87,33 +66,44 @@ class XtextBuilderPlugin implements Plugin { ] } - private def inferXtextClasspath(XtextSourceDirectorySet sourceSet, FileCollection classpath) { - xtext.classpathInferrers.fold(xtextLanguages as FileCollection) [ newXextClasspath, inferrer | - inferrer.inferXtextClasspath(sourceSet, newXextClasspath, classpath) + private def setupXtextClasspath(XtextSourceDirectorySet sourceSet, XtextGenerate generatorTask) { + val xtextTooling = project.configurations.create(sourceSet.qualifyConfigurationName("xtextTooling")) + generatorTask.xtextClasspath = xtextTooling + xtextTooling.extendsFrom(xtextLanguages) + xtextTooling.exclude(#{"group" -> "asm"}) + #[ + 'org.eclipse.xtext:org.eclipse.xtext', + 'org.eclipse.xtext:org.eclipse.xtext.smap', + 'org.eclipse.xtext:org.eclipse.xtext.xbase', + 'org.eclipse.xtext:org.eclipse.xtext.java' + ].forEach[project.dependencies.add(xtextTooling.name, it)] + val xtextVersion = new LazyXtextVersion(xtext, xtextLanguages, generatorTask) + xtextTooling.withDependencies [ + val version = xtextVersion.getVersion + if (version === null) { + return + } + if (project.supportsJvmEcoSystemplugin && new ComparableVersion(version) >= new ComparableVersion("2.17.1")) { + add(project.dependencies.enforcedPlatform('''org.eclipse.xtext:xtext-dev-bom''')) + } ] - } - - private def automaticallyInferXtextCoreClasspath() { - xtext.classpathInferrers += new XtextClasspathInferrer() { - override inferXtextClasspath(XtextSourceDirectorySet sourceSet, FileCollection xtextClasspath, FileCollection classpath) { - val version = xtext.getXtextVersion(classpath) ?: xtext.getXtextVersion(xtextClasspath) - if (version === null) { - throw new GradleException('''Could not infer Xtext classpath, because xtext.version was not set and no xtext libraries were found on the «classpath» classpath''') - } - val xtextTooling = project.configurations.create(sourceSet.qualifyConfigurationName("xtextTooling")) - xtextTooling.dependencies += #[ - 'org.eclipse.xtext:org.eclipse.xtext', - 'org.eclipse.xtext:org.eclipse.xtext.smap', - 'org.eclipse.xtext:org.eclipse.xtext.xbase', - 'org.eclipse.xtext:org.eclipse.xtext.java', - 'org.eclipse.jdt:org.eclipse.jdt.core:3.10.0' - ] - .map[project.dependencies.create(it)] - xtext.makeXtextCompatible(xtextTooling) - xtext.forceXtextVersion(xtextTooling, version) - xtextTooling.plus(xtextClasspath) + xtextTooling.resolutionStrategy.eachDependency [ + val version = xtextVersion.getVersion + if (version === null) { + return } - } + if (requested.group == "org.eclipse.xtext" || requested.group == "org.eclipse.xtend") + useVersion(version) + + if (!project.supportsJvmEcoSystemplugin || new ComparableVersion(version) < new ComparableVersion("2.17.1")) { + if (requested.group == "com.google.inject" && requested.name == "guice") + useVersion("5.0.1") + if (requested.name == "org.eclipse.equinox.common") + useTarget("org.eclipse.platform:org.eclipse.equinox.common:3.13.0") + if (requested.name == "org.eclipse.core.runtime") + useTarget("org.eclipse.platform:org.eclipse.core.runtime:3.19.0") + } + ] } private def configureOutletDefaults() { @@ -179,4 +169,27 @@ class XtextBuilderPlugin implements Plugin { } ] } + + private static class LazyXtextVersion { + val XtextExtension xtext + val Configuration languages + val XtextGenerate task + var String version + + new (XtextExtension xtext, Configuration languages, XtextGenerate task) { + this.xtext = xtext + this.languages = languages + this.task = task + } + + def String getVersion() { + if (version === null) { + version = xtext.getXtextVersion(task.classpath) ?: xtext.getXtextVersion(languages) + if (version === null && !task.mainSources.empty) { + throw new GradleException('''Could not infer Xtext classpath for «task», because xtext.version was not set and no xtext libraries were found in «task.classpath» or «languages»''') + } + } + version + } + } } diff --git a/xtext-gradle-plugin/src/main/java/org/xtext/gradle/tasks/XtextClasspathInferrer.java b/xtext-gradle-plugin/src/main/java/org/xtext/gradle/tasks/XtextClasspathInferrer.java deleted file mode 100644 index 19b899fa..00000000 --- a/xtext-gradle-plugin/src/main/java/org/xtext/gradle/tasks/XtextClasspathInferrer.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.xtext.gradle.tasks; - -import org.gradle.api.file.FileCollection; - -public interface XtextClasspathInferrer { - - public FileCollection inferXtextClasspath(XtextSourceDirectorySet sourceSet, FileCollection xtextClasspath, FileCollection classpath); -} diff --git a/xtext-gradle-plugin/src/main/java/org/xtext/gradle/tasks/XtextExtension.xtend b/xtext-gradle-plugin/src/main/java/org/xtext/gradle/tasks/XtextExtension.xtend index dd6a7c65..cac80001 100644 --- a/xtext-gradle-plugin/src/main/java/org/xtext/gradle/tasks/XtextExtension.xtend +++ b/xtext-gradle-plugin/src/main/java/org/xtext/gradle/tasks/XtextExtension.xtend @@ -1,19 +1,15 @@ package org.xtext.gradle.tasks; import com.google.common.base.CaseFormat -import com.google.common.collect.Lists import java.io.File -import java.util.List import java.util.Map import java.util.Set import java.util.regex.Pattern -import org.apache.maven.artifact.versioning.ComparableVersion import org.eclipse.xtend.lib.annotations.Accessors import org.gradle.api.Action import org.gradle.api.Named import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.Project -import org.gradle.api.artifacts.Configuration import org.gradle.api.file.FileCollection import org.gradle.api.tasks.Input import org.gradle.api.tasks.Internal @@ -29,7 +25,6 @@ class XtextExtension { @Accessors String version @Accessors val NamedDomainObjectContainer sourceSets @Accessors val NamedDomainObjectContainer languages; - @Accessors val List classpathInferrers; Project project @@ -37,7 +32,6 @@ class XtextExtension { this.project = project sourceSets = project.container(XtextSourceDirectorySet)[name|project.instantiate(DefaultXtextSourceDirectorySet, name, project, this)] languages = project.container(Language)[name|project.instantiate(Language, name, project)] - classpathInferrers = Lists.newArrayList } def sourceSets(Action> configureAction) { @@ -68,30 +62,6 @@ class XtextExtension { return matcher.group(2) } } - - def void forceXtextVersion(Configuration dependencies, String xtextVersion) { - dependencies.resolutionStrategy.eachDependency [ - if (requested.group == "org.eclipse.xtext" || requested.group == "org.eclipse.xtend") - useVersion(xtextVersion) - ] - - if (project.supportsJvmEcoSystemplugin && new ComparableVersion(xtextVersion)>= new ComparableVersion("2.17.1")) { - dependencies.dependencies += project.dependencies.enforcedPlatform('''org.eclipse.xtext:xtext-dev-bom:«xtextVersion»''') - } else { - dependencies.resolutionStrategy.eachDependency [ - if (requested.group == "com.google.inject" && requested.name == "guice") - useVersion("5.0.1") - if (requested.name == "org.eclipse.equinox.common") - useTarget("org.eclipse.platform:org.eclipse.equinox.common:3.13.0") - if (requested.name == "org.eclipse.core.runtime") - useTarget("org.eclipse.platform:org.eclipse.core.runtime:3.19.0") - ] - } - } - - def void makeXtextCompatible(Configuration dependencies) { - dependencies.exclude(#{'group' -> 'asm'}) - } } @Accessors