Error when updating XText versions for Gradle 6 - gradle

I am attempting to update an EMF/XCore project to newer versions to get around a versioning roadblock. Currently the repository that houses this project must target Gradle 4 and Bndtools 4.3 because of problems when targeting newer versions. I readily admit that a problem here is my lack of understanding of XText, XCore, and otherwise. Now I find myself on a machine without access to Java 8 which has forced an attempt to update the project settings if at all possible.
The last safe targets for this project were XText 2.16.0 and org.xtext.builder version 1.0.21. The examples I have been able to locate match the settings of this project for the most part.
So now, attempting to run in a Gradle 6.3 environment with OpenJDK 13 (if the Java version is the issue that can be changed)...
Notes
Some changes are based on researching solutions to my build problem and some comments are added
${mavenURL} is currently pointing to Maven Central
I added the compile platform() line based on XText's Release notes. It does not seem to help this issue, though
I changed version numbers to match those found in the Maven BOM
I have attempted various combinations of changing the org.xtext.builder version as well as targeting both EMF 2.21 and 2.20
I have tried a lower XText version. 2.17.0 fails with a different issue
build.gradle:
plugins {
id 'org.xtext.builder' version '2.0.8'
id 'java' // Helpful? Doesn't appear so
}
repositories {
maven() {
url "${mavenURL}"
}
}
ext.xtextVersion = "2.21.0"
ext.emfVersion = "2.20.0"
dependencies {
compile platform("org.eclipse.xtext:xtext-dev-bom:${xtextVersion}")
xtextLanguages 'org.eclipse.emf:org.eclipse.emf.codegen.ecore.xtext:1.4.0'
xtextLanguages('org.eclipse.emf:org.eclipse.emf.ecore.xcore:1.12.0') {
exclude group: 'org.antlr', module: 'antlr-runtime'
}
xtextLanguages "org.eclipse.xtext:org.eclipse.xtext.ecore:${xtextVersion}"
xtextLanguages "org.eclipse.xtext:org.eclipse.xtext.xbase.lib:${xtextVersion}"
xtextLanguages 'org.eclipse.emf:org.eclipse.emf.codegen:2.19.0'
xtextLanguages 'org.eclipse.emf:org.eclipse.emf.codegen.ecore:${emfVersion}'
xtextLanguages 'org.eclipse.emf:org.eclipse.emf.mwe2.runtime:2.11.2'
compile "org.eclipse.xtext:org.eclipse.xtext:${xtextVersion}"
compile "org.eclipse.xtext:org.eclipse.xtext.xbase:${xtextVersion}"
compile 'org.eclipse.emf:org.eclipse.emf.ecore.xcore.lib:1.4.0'
}
xtext {
version = "${xtextVersion}"
languages {
ecore {
setup = 'org.eclipse.xtext.ecore.EcoreSupport'
}
codegen {
setup = 'org.eclipse.emf.codegen.ecore.xtext.GenModelSupport'
}
xcore {
setup = 'org.eclipse.emf.ecore.xcore.XcoreStandaloneSetup'
generator.outlet.producesJava = true
// Have also tried generator.javaSourceLevel = '1.8'
}
}
sourceSets {
main {
srcDir 'model'
// Move the generated Xcore output to the src directory
output {
dir(xtext.languages.xcore.generator.outlet, 'src-gen')
}
}
}
}
Multiple tries have ended up resulting in the following error:
> ./gradlew jar
...
> Task :com.example.project:generateXtext FAILED
ERROR:A generic type in this context must refer to a classifier or a type parameter (file:...file.xcore)
...
> Xtext validation failed, see build log for details.
for a multitude of lines. The XCore file looks something like this
#GenModel(
complianceLevel="8.0",
loadInitialization="false",
modelDirectory="com.example.project/src-gen",
bundleManifest="false",
updateClasspath="false",
oSGiCompatible="true",
forceOverwrite="true")
#Ecore(
nsPrefix="query",
nsURI="something"
)
// These lines had to be added to resolve the above annotations no longer working
annotation "http://www.eclipse.org/emf/2002/GenModel" as GenModel
annotation "http://www.eclipse.org/emf/2002/Ecore" as Ecore
interface Node wraps an.external.Node {}
abstract class ENode extends Node
{
op Object getParent() // This line fails due to not referring to object or classifier
{
eContainer
}
}
I have seen this error pop up in bug reports on XText sites (such as https://github.com/eclipse/xtext-maven/issues/71), and they were resolved. But generally the projects reference Github examples such as https://github.com/itemis/itemis-blog/tree/xcore_gradle or https://github.com/ghillairet/xcore-gradle-example which both point to versions of XText and the corresponding builder which were indeed working prior to this upgrade attempt.
The project is an XText project. Relevant portion of the .project file is here:
<buildSpec>
<buildCommand>
<name>bndtools.core.bndbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>bndtools.core.bndnature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
<nature>org.eclipse.pde.PluginNature</nature>
</natures>
Any help would be appreciated.

I received assistance from the folks working on the XText Gradle plug-in via https://github.com/xtext/xtext-gradle-plugin/issues/171.
The biggest issue is that src-gen cannot exist on the classpath prior to execution of the generateXText task. To assist with this updating the clean task to remove the src-gen folder is recommended. Additionally, the second 3 compile dependencies should be xtextLanguages dependencies.

Related

Gradle Idea plugin - issues with specifing test sources

I'm trying to create a custom source set and mark its contents in Intellij Idea as a Test Sources Root. I tried to use idea plugin and do it according to the gradle official website but it is not clear for me how it works.
First of all the documentation specifies the following configuration setup
idea {
module {
testSources.from(sourceSets["intTest"].java.srcDirs)
}
}
When I try to use it i receive Unresolved reference: testSources. Where is it coming from?
Then I tried to use:
idea {
module {
testSourceDirs = intTest.java.srcDirs
}
}
it works fine as long as I use only Java. After applying Kotlin plugin however, both kotlin and java + resources folder are again treated as Sources Root not Test Sources. To fix that I had to change from:
testSourceDirs = intTest.java.srcDirs
to:
testSourceDirs = intTest.kotlin.srcDirs
and now all folders are Test Source Root again. Since kotlin.srcDirs also includes java.srcDirs it looks like you have to specify all, otherwise it is ignored...
Now the real issue came when I used gradle-avro-plugin. Applying it made my folders marked as Sources Root again. I believe it is because it adds another avro directory, but just to main source set.
Does anyone know how to make it marked as Test Sources having both kotlin and avro plugin applied? Am I doing something wrong here? Beacause this beheviour seems to be buggy in the first place.
Tested with:
IntelliJ IDEA 2022.3.1 (Ultimate Edition)
Gradle 6.8.3 and 7.4.2
Plugin id("com.github.davidmc24.gradle.plugin.avro") version "1.5.0"
Plugin kotlin("jvm") version "1.7.0"

Gradle7 Version Catalog: How to use it with buildSrc?

I am very excited about the incubating Gradle's version catalogs and have been experimenting with it. I’ve found that the information in my gradle/libs.versions.toml is accessible in the build.gradle.kts scripts for my app and utility-lib projects.
However, I am unable to use the content of the toml file for buildSrc/build.gradle.kts or the convention files.
The only way that I could build was to hard-code the dependencies into those files, as I did before the version catalog feature.
In the buildSrc folder, I created a settings.gradle.kts file and inserted the dependencyResolutionManagement code for versionCatalogs, which is pointing to the same file as for my app and utility-lib projects.
Based on the Gradle7 docs, it seems that sharing a version catalog with buildSrc and modules is possible… I’d appreciate a nudge into getting it to work with buildSrc, if possible.
Here is a simple sample project, which I created via gradle init: my-version-catalog
Thank you for your time and help,
Mike
With Gradle 7.3.3, it is possible. Note version catalogs are GA since Gradle 7.4
The code snippet assumes Gradle is at least 7.4, but if you need them prior that version, insert enableFeaturePreview("VERSION_CATALOGS") at the beginning of each settings.gradle.kts.
Using buildSrc
buildSrc/settings.gradle.kts
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
buildSrc/build.gradle.kts
dependencies {
implementation(libs.gradleplugin.intellij) // <- the lib reference
}
You can even use the version catalog for plugins
gradle/libs.versions.toml
...
[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
jetbrains-changelog = { id = "org.jetbrains.changelog", version.ref = "changelog-plugin" }
jetbrains-intellij = { id = "org.jetbrains.intellij", version.ref = "intellij-plugin" }
hierynomus-license = { id = "com.github.hierynomus.license", version.ref = "license-plugin" }
nebula-integtest = { id = "nebula.integtest", version.ref = "nebula-integtest-plugin" }
build.gradle.kts
plugins {
id("java")
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.nebula.integtest)
alias(libs.plugins.jetbrains.intellij)
alias(libs.plugins.jetbrains.changelog)
alias(libs.plugins.hierynomus.license)
}
Note for accessing the catalog within scripts, please refer to the below section, the trick is the same.
Using convention plugins and included build
In the main project include a the Gradle project that holds the convention plugins.
build.gradle.kts
includeBuild("convention-plugins") // here it's a subfolder
convention-plugins/settings.gradle.kts
dependencyResolutionManagement {
repositories {
gradlePluginPortal()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
rootProject.name = "convention-plugins"
The trick to enable convention plugins to access the version catalog is split in two part, add an ugly implementation dependency that locate where the version catalog generated classes are located.
libs.javaClass.superclass.protectionDomain.codeSource.location
Then in the convention plugin refer to the libs extension via Project::the.
val libs = the<LibrariesForLibs>()
This is tracked by gradle/gradle#15383.
convention-plugins/build.gradle.kts
plugins {
`kotlin-dsl`
}
dependencies {
implementation(libs.gradleplugin.kotlin.jvm)
// https://github.com/gradle/gradle/issues/15383
implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
}
And in the actual convention plugin
import org.gradle.accessors.dm.LibrariesForLibs
plugins {
id("org.jetbrains.kotlin.jvm")
}
// https://github.com/gradle/gradle/issues/15383
val libs = the<LibrariesForLibs>()
dependencies {
detektPlugins(libs.bundles.kotlinStuff) // access catalog entries
}
The org.gradle.accessors.dm.LibrariesForLibs class is generated by gradle is somewhere in local gradle folder ./gradle/<version>/dependency-accessors/<hash>/classes
Quick note that older IntelliJ IDEA currently (2022.3) reports alias(libs.gradleplugin.thePlugin) as an error in the editor,
although the dependencies are correctly resolved.
This tracked by KTIJ-19369, the ticket indicates this is actually a bug in Gradle Kotlin DSL gradle/gradle#22797, and someone made a simple IntelliJ IDEA plugin to hide this error until resolved.
Brice, it looks like a can of worms to go down that path, particularly for my situation, where I'm trying to use a libs.version.toml file from an android project, but the custom plugin is of course from a java/kotlin project. I tried creating the libs file by hardwiring the path to the toml file in the custom plugin. It might work if both were java projects, but I never tried that since that's not what I'm after. The ideal solution would be for the plugin to use the libs file from the project it is applied to, but it looks like the version catalog needs to be created in the settings file, before you even have access to "Project", so that's why you would have to hardwire the path.
Short answer. No, but there are other techniques for a custom plugin to get project version data from the project it is applied to.

Gradle cannot find prefix version transitive dependency which does not exist

I have a multi-module gradle project where in a module I add dependencies in compile configuration on runtime.
Those dependencies fetch a transitive dependency with a version prefix that does not exist.
So case is like this
compile 'group:moduleA:version.+'
This moduleA downloads moduleB with same version.+ prefix notation and that downloads another moduleC with same prefix notation, moduleC is present in artifactory with version 10 and above and 8 and below, so there are no versions which are number 9, and gradle insist on finding moduleC with version 9, it doesn't fetch versions above or below it.
How can I make gradle fetch another version if the version its trying to find is not there?
Please comment for any clarification and thanks for helping.
EDIT: Want to clarify that + in version part is not resolving to a number which is correct and present on artifactory, like 9.1 or 9.12.
gradle determines this version, which is incorrect like 9.1 is present but it resolves to 9.2 or some other number which is not there.
EDIT2: Task which is used to fetch dependencies and then add them in compile configuration.
task addAdditionalDependencies {
doLast {
Object slurper = new JsonSlurper().parseText(api.jsonResponse())
Set<String> dependencyNames = configurations.compile.dependencies.collect { it.name }
List<Map<String, String>> artifactPaths = slurper.results.collect {
String[] pathSegments = it.path.split('/')
if (!dependencyNames.contains(pathSegments[1]) && project.name != pathSegments[1]) {
[group: pathSegments[0],
name: pathSegments[1],
version: "version.+",
configuration: 'compile']
} else [:]
}
artifactPaths.each {
if (!it.isEmpty()) {
project.dependencies.add('compile', it)
}
}
// we have to call this because app does not have any source files and so compileJava does not download
// dependencies
configurations.compile.files
}
}
When using a version like 9.+, Gradle will looks for all version that matches the prefix, that is the part before the +.
There is however no way to make Gradle ignore that part in case no such version exist.
If the version of moduleC can be anything, then you could simply use + without any prefix.
Note that doing something like that could expose you to breakage in a build even though nothing changed, aside from a new version of moduleC being published.
You could also combine this dynamic version resolution with dependency locking to have a finer grained control on when to upgrade moduleC.

WIthin nebula/gradle, how can I inject the version being released into the jar being published?

We have a tool that runs from the command line. One of the commands is -version.
Before we converted to the nebula release plugin, the version was in the gradle.properties file, and as part of the build we copied it from there to a src/main/resources/version.txt file, that was later read by the tool to output the version.
But now the version is never in a file that's checked into git. Instead, it is only known during the nebula release process.
We want to obtain that version during the nebula release process and inject it into the jar that nebula is about to publish. For example, it could be added to the manifest.
We've tried to figure out how to do this, but don't see any examples online, and nothing about it in the documentation.
Simply create a task that caches the version that is dynamically inferred by Nebula.
Since you originally copied/created src/main/resources/version.txt, we'll use that that model our task.
Assuming a simple/standard Java project, using the Kotlin DSL:
val cacheNebulaVersion by tasks.registering {
mustRunAfter(tasks.named("release"))
doLast {
val sourceSets = project.extensions.getByName("sourceSets") as SourceSetContainer
sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).output.resourcesDir?.let {
// If there are not existing resources in your project then you must create
// the resources dir otherwise a FileNotFoundException will be thrown.
if (!it.exists()) {
it.mkdirs()
}
File(it, "version.txt").printWriter().use { out ->
out.println(project.version)
}
}
}
}
When I invoke ./gradlew clean build snapshot cacheNebulaVersion, the version produced by Nebula is cached/created at src/main/resources/version.txt in the build output. The task above does not bundle it with the jar.
Hopefully that gives you an idea what to do.

The DefaultSourceDirectorySet constructor has been deprecated. How to use the ObjectFactory service?

I recently updated to gradle version 5.0-rc-4, and when running ./gradlew assemble (or any other task) I now get the following message:
Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
When I use ./gradlew assemble --warning-mode all I get:
> Configure project :
The DefaultSourceDirectorySet constructor has been deprecated. This is scheduled to be removed in Gradle 6.0. Please use the ObjectFactory service to create instances of SourceDirectorySet instead.
But in the following build.gradle I don't see where I'm using any DefaultSourceDirectorySet, so what is this warning about, and what would I need to change to be compatible with Gradle 6.0?
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.10'
}
dependencies {
compile 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
}
repositories {
mavenCentral()
mavenLocal()
jcenter()
}
Related
I found create version.txt file in project dir via build.gradle task(gradle 5.0) but I don't have constructs like that so I don't know how it would apply.
I found this deprecation mentioned in the release notes at https://docs.gradle.org/5.0-milestone-1/release-notes.html but they say
In this release of Gradle, the ObjectFactory service, which is part of the public API, now includes a method to create SourceDirectorySet instances. Plugins can now use this method instead of the internal types.
but I don't see how.
I also found the SourceDirectorySet interface at https://docs.gradle.org/current/javadoc/org/gradle/api/file/SourceDirectorySet.html but I don't see how to use it.
Template repository: https://github.com/PHPirates/kotlin-template-project
Update 2019-01-23 Five minutes ago, kotlin 1.3.20 was released and also updated in the Gradle repository so this issue should be solved by updating the Kotlin Gradle plugin to 1.3.20.
Update 2019-01-11 The target version in Youtrack issue KT-26808 has just been updated to 1.3.20. You can view the latest released version in the Gradle repositories here, but at the moment there are still a lot of open issues for 1.3.20.
Update 2018-12-17 The deprecation warning is fixed in commit https://github.com/JetBrains/kotlin/commit/67e82a54e5ee529116e881953f93a4c8f216e33a, the Youtrack issue is closed. Now waiting for a release to roll out.
As #Javaru pointed out, this has already been reported (in september 2018) at Youtrack issue KT-26808.
Using information from Lance's comment in the link that Thomas David Baker pointed to:
Answer:
If you get this warning while you are not using DefaultSourceDirectorySet directly, this is probably coming from a Gradle plugin you use. You could check this using the --warning-mode all --stacktrace flags for the Gradle build, so like ./gradlew assemble --warning-mode all --stacktrace.
In this particular case it's the Kotlin Gradle Plugin, they use it at DefaultKotlinSourceSet.kt#L140-L155:
private val createDefaultSourceDirectorySet: (name: String?, resolver: FileResolver?) -> SourceDirectorySet = run {
val klass = DefaultSourceDirectorySet::class.java
val defaultConstructor = klass.constructorOrNull(String::class.java, FileResolver::class.java)
if (defaultConstructor != null && defaultConstructor.getAnnotation(java.lang.Deprecated::class.java) == null) {
// TODO: drop when gradle < 2.12 are obsolete
{ name, resolver -> defaultConstructor.newInstance(name, resolver) }
} else {
// (code omitted)
}
}
We can trust that they will resolve the issue in time, so don't worry about the warning.

Resources