Antlr4 - generate grammar source for more language in gradle - gradle

In my project I have to generate the grammar sources for more than one language (Java, Javascript and Python) using gradle.
I'm using the antlr plugin, so I have the following rows in my build.gradle file:
apply plugin: 'antlr'
generateGrammarSource {
def languageFlag = project.hasProperty('Language') ?project.property('Language') : 'Python2'
arguments = ['-Dlanguage=' + languageFlag]
def pythonOutputDirectory = "python/engine_lib/kpi_attributes"
switch (languageFlag) {
case "Java":
outputDirectory = file("../../../../XSpotterGUI/sviluppo/src/com/xech/xspotter4/grammars/kpiattributes")
arguments += ['-package', 'com.xech.xspotter4.grammars.kpiattributes']
break
case "JavaScript":
outputDirectory = file("../../../../XSpotterGUI/sviluppo/WebContent/xspotter4/js/xech/grammars/kpiattributes")
break
case "Python2":
outputDirectory = file(pythonOutputDirectory)
break
}
description = 'Generates Java sources from Antlr4 grammars.'
maxHeapSize = "64m"
sourceSets.main.antlr.srcDirs = ['.']
includes = ['KpiAttributes.g4']
doLast {
if (languageFlag.equals("Python2")) {
File file = new File("$pythonOutputDirectory/__init__.py")
file.write ""
}
}
}
I omitted the rows regarding repositories, dependencies and so on.
In this way I'm able to call gradle three times:
./gradlew generateGrammarSource -PLanguage=Java
./gradlew generateGrammarSource -PLanguage=Python2
./gradlew generateGrammarSource -PLanguage=JavaScript
But I have not been able to create a task 'generateAllGrammarSources' in order to call gradlew only ONE time and generate all sources

Related

How to add multiple tasks of the same type in Gradle?

I need to generate FlatBuffers files from *.fbs file before the build.
So i'm using gradle.plugin.io.netifi:gradle-flatbuffers-plugin:1.0.7 to do it for me.
It works as expected for 1 task:
def generatedSourcePathJava = "$buildDir/generated/source/flatbuffers/java"
def generatedSourcePathCpp = "$buildDir/generated/source/flatbuffers/cpp"
...
task createFlatBuffersJava(type: io.netifi.flatbuffers.plugin.tasks.FlatBuffers) {
outputDir = file(generatedSourcePathJava)
language = "kotlin"
}
build.dependsOn createFlatBuffersJava
But if i add the 2nd one (to generate C++ files for JNI):
task createFlatBuffersJava(type: io.netifi.flatbuffers.plugin.tasks.FlatBuffers) {
outputDir = file(generatedSourcePathJava)
language = "kotlin"
}
task createFlatBuffersCpp(type: io.netifi.flatbuffers.plugin.tasks.FlatBuffers) {
outputDir = file(generatedSourcePathCpp)
language = "cpp"
}
assemble.dependsOn createFlatBuffersJava, createFlatBuffersCpp
Gradle build (../gradlew :engine-flatbuffers:clean :engine-flatbuffers:build) fails with the following:
What went wrong:
A problem occurred configuring project ':engine-flatbuffers'.
java.util.ConcurrentModificationException (no error message)
I think the question can be generalized to "How to add multiple tasks of the same type in Gradle?".
PS. "gradle-5.6-all"
That's a known plugin bug/feature reported at https://github.com/gregwhitaker/gradle-flatbuffers-plugin/issues/7.
It works in 1.0.5 but kotlin [argument] is sadly not supported there at that point. java works and it's compatible.

Gradle configure task based on subproject property

I'm trying to configure a Zip task based on one of the property inside sub-projects, but the property is not yet accessible at the time of configuring the task. For instance, I want to exclude all my projects that has toexclude = true from my zip file. So, the build.gradle of the sub-projects that I want to exclude starts with this:
ext.toexclude = true;
...
And my main build.gradle has this task:
task zipContent (type: Zip){
def excludedProjects = allprojects.findAll{Project p -> p.toexclude == true}.collect{it.name}
println excludedProjects
destinationDir = "/some/path"
baseName = "myFile.zip"
exclude excludedProjects
from "/some/other/path"
}
The problem is that excludedProjects is always empty. Indeed, when I am executing the task, I can see []. I believe this is due to the fact that the property that I set in the subproject's build.gradle is not available at the moment the task is configured. As a proof, if I replace the first line of the task by this:
def excludedProjects = allprojects.collect{it.name}
The task prints out all of my project's name, and the zip contains nothing (which means the problem is in the p.toexclude == true).
Also, if I try this:
task zipContent (type: Zip){
def excludedProjects = []
doFirst{
excludedProjects = allprojects.findAll{Project p -> p.toexclude == true}.collect{it.name}
println "IN DOFIRST"
println excludedProjects
}
println "IN TASK CONFIG"
println excludedProjects
destinationDir = "/some/path"
baseName = "myFile.zip"
exclude excludedProjects
from "/some/other/path"
}
The task prints out IN TASK CONFIG followed by an empty array, then IN DOFIRST with the array containing only the subprojects that I set ext.toexclude == true.
So, is there a way to get the properties of the sub-projects at configuration time?
Well, the crucial question is: At which point of the build is all necessary information available?
Since we want to know each project in the build, where the extra property toexclude is set to true and it is possible (and by design) that the property is set via the build script, we need each build script to be evaluated.
Now, we have two options:
By default, subprojects are evaluated after the parent (root) project. To ensure the evaluation of each project, we need to wait for the point of the build, where all projects are evaluated. Gradle provides a listener for that point:
gradle.addListener(new BuildAdapter() {
#Override
void projectsEvaluated(Gradle gradle) {
tasks.getByPath('zipContent').with {
exclude allprojects.findAll { it.toexclude }.collect{ it.name }
}
}
})
Gradle provides the method evaluationDependsOnChildren(), to turn the evaluation order around. It may be possible to use your original approach by calling this method before querying the excluded projects. Since this method only applies on child projects, you may try to call evaluationDependsOn(String) for each project in the build to also apply for 'sibling' projects. Since this solution breaks Gradle default behavior, it may have undesired side effects.
Just define excludedProjects outside the task
def excludedProjects = allprojects.findAll{Project p -> p.toexclude == true}.collect{it.name}
task zipContent (type: Zip){
destinationDir = file("/some/path")
baseName = "myFile.zip"
exclude excludedProjects
from "/some/other/path"
}
You can call evaluationDependsOnChildren() in the root project so that child projects are evaluated before the root
Eg
evaluationDependsOnChildren()
task zipContent (type: Zip) { ... }
Another option is to use an afterEvaluate { ... } closure to delay evaluation
Eg:
afterEvaluate {
task zipContent (type: Zip) { ... }
}

apply plugin in gradle

I have a quick question on how to formulate my logic to apply custom parameters in my gradle build file.
I want to apply my plugin with the given parameters for each file in a specified directory location.
How might I accomplish this?
UPDATED
build.gradle:
apply plugin: 'quick.plugin'
task applyPluginXMLOne(type: com.nav.QuickFixTask){
quickfixPlugin.dictFile = file("${projectDir}/src/main/resources/custom.xml")
quickfixPlugin.decimal = true
quickfixPlugin.outputDirectory = file("${buildDir}/generated/")
quickfixPlugin.schemaDirectory = file("${projectDir}/src/main/resources/quickfix/generated")
}
task applyPluginXMLTwo(type: com.nav.QuickFixTask){
quickfixPlugin.dictFile = file("${projectDir}/src/main/resources/custom2.xml")
quickfixPlugin.decimal = true
quickfixPlugin.outputDirectory = file("${buildDir}/generated/")
quickfixPlugin.schemaDirectory = file("${projectDir}/src/main/resources/quickfix/codegen")
}
applyPluginXMLTwo.mustRunAfter applyPluginXMLOne
The result when I run $ gradle applyPluginXMLOne applyPluginXMLTwo
:
This is my output dictFile C:\dev\src\main\resources\custom2.xml
This is my output outputDirectory C:\dev\build\generated
This is my output orderedFields false
This is my output decimal true
:applyPluginXMLTwo
This is my output dictFile C:\dev\src\main\resources\custom2.xml
This is my output outputDirectory C:\dev\build\generated
This is my output orderedFields false
This is my output decimal true
BUILD SUCCESSFUL
Total time: 2.299 secs
In order to apply the plugin one after the other I needed to add a `build.finalizedBy(task1,task2) portion as shown below.
build.gradle:
apply plugin: 'quick.plugin'
task applyPluginXMLOne(type: com.nav.QuickFixTask){
quickfixPlugin.dictFile = file("${projectDir}/src/main/resources/custom.xml")
quickfixPlugin.decimal = true
quickfixPlugin.outputDirectory = file("${buildDir}/generated/")
quickfixPlugin.schemaDirectory = file("${projectDir}/src/main/resources/quickfix/generated")
}
task applyPluginXMLOne(type: com.nav.QuickFixTask){
quickfixPlugin.dictFile = file("${projectDir}/src/main/resources/custom2.xml")
quickfixPlugin.decimal = true
quickfixPlugin.outputDirectory = file("${buildDir}/generated/")
quickfixPlugin.schemaDirectory = file("${projectDir}/src/main/resources/quickfix/codegen")
}
build.finalizedBy(applyPluginXMLOne,applyPluginXMLOne)

How can I read Gradle metadata in a Jenkinsfile

Within my Jenkinsfile I would like to read some metadata from a Gradle buildscript, e.g. group, baseNameand version. With Maven, I can do something like this:
def pom = readMavenPom file: 'pom.xml'
env.POM_VERSION = pom.version
env.POM_ARTIFACT_ID = pom.artifactId
env.POM_GROUP_ID = pom.groupId
Question is: how can I do the same thing with Gradle, given I have a build.gradle that looks like this:
ext {
group = 'my.group.com'
baseName = 'myapplication'
version = '0.5.2-SNAPSHOT'
}
Maybe there is a "trick" to read Gradle build information in a Jenkinsfile since both is Groovy, but I am a Groovy newb :)

How to call a task in another sub project build file with parameters

I'm working on creating a multi project build file using Gradle. Many sub projects need to execute a task which exists in another sub project by passing in certain parameters. How can this be achieved in Gradle?
for example :
root project
- project B : task X
- project A : task Y (param m, param n)
I need projectB.taskX to call projectA.taskY(m,n)
Update:
Sub-Project A has a task of type JavaExec which needs an input parameter to the location of the properties file
task generateCode(dependsOn:['classes','build'], type: JavaExec) {
main = 'jjrom.ObjectGen'
classpath = sourceSets.main.runtimeClasspath
args 'arg1', 'arg2', file(propertiesFilePath).path
}
Now, there are 10 sub projects, all of which need to call this task 'generateCode' with a parameter that contains the location to the properties file. Also, this task should be executed before building each sub-project which can be achieved using dependsOn.
My java project code organisation:
trunk/
projA/src/java/../ObjectGen.java
projB/src/java/../properties.xml
projC/src/java/../properties.xml
projD/src/java/../properties.xml
....
A task cannot call another task. Instead, the way to solve this problem is to add a generateCode task to all ten subprojects. You can do this from the root build script with code similar to the following:
subprojects {
apply plugin: 'java'
configurations {
codegen
}
dependencies {
// A contains the code for the code generator
codegen project(':A')
}
task generateCode(type: JavaExec) {
main = 'jjrom.ObjectGen'
classpath = configurations.codegen
args 'arg1', 'arg2'
}
compileJava.dependsOn(generateCode)
}
If there is no general pattern as to where the properties file is located, this information can be added in the subprojects' build scripts:
generateCode {
args file('relative/path/to/properties/file')
}

Resources