Gradle: Trying to figure out an EOF error. Userguide: Example 14.5. Configuring arbitrary objects using a script. - gradle

I am on page 78 of the gradle userguide: Example 14.5. Configuring arbitrary objects using a script.
I have copied all of the code in the example:
build.gradle
task configure << {
pos = java.text.FieldPosition( ) new 10
// Apply the script
apply from: 'other.gradle', to: pos
println pos.beginIndex
println pos.endIndex
}
other.gradle
beginIndex = 1;
endIndex = 5;
Output of gradle -q configure
D:\Gradle\ThisAndThat>gradle -q configure
FAILURE: Build failed with an exception.
Where: Build file 'D:\Gradle\ThisAndThat\build.gradle' line: 1
What went wrong: Could not compile build file 'D:\Gradle\ThisAndThat\build.gradle'.
> startup failed:
build file 'D:\Gradle\ThisAndThat\build.gradle': 1: expecting EOF, found 'configure' # line 1, column 6.
task configure << { ^
1 error
I cannot figure out why I am getting this error. Any help would be appreciated. Thanks!

When I literally copy the code from Chapter 14.5 of the userguide it works. Your mistake is in the build.gradle script:
task configure << {
pos = java.text.FieldPosition( ) new 10
should be
task configure << {
pos = new java.text.FieldPosition(10)

Related

Can't invoke method from initscript

If I change my ~/.gradle/init.gradle to the following:
def hi() {
println "hello"
}
hi()
initscript {
}
Then running a gradle build outputs:
hello
> Task :prepareKotlinBuildScriptModel UP-TO-DATE
BUILD SUCCESSFUL in 366ms
But if I change ~/.gradle/init.gradle to this:
def hi() {
println "hello"
}
initscript {
hi()
}
Then the gradle build outputs:
FAILURE: Build failed with an exception.
* Where:
Initialization script '~/.gradle/init.gradle' line: 6
* What went wrong:
A problem occurred evaluating initialization script.
> Could not find method hi() for arguments [] on object of type org.gradle.api.internal.initialization.DefaultScriptHandler.
Why is this?
And how can I invoke hi() from within the initscript block?
see link below to understand the initscript closure better - in short you can not do actions inside; you can only configure - see diff example of linking actions to tasks https://docs.gradle.org/current/userguide/init_scripts.html#sec:writing_an_init_script
Credit to ephemient from the Gradle community-support slack channel:
buildscript, initscript, plugins, and pluginManagement are all
special blocks that extracted and run separately, before any other
part of the script. this is necessary because Gradle needs to use them
to set up the build environment for the rest of the script. you cannot
use anything defined outside of the block, in these blocks.
Another note: if I change init.gradle to
initscript {
def hi() {
println "hello"
}
hi()
}
then the following error is output:
FAILURE: Build failed with an exception.
* Where:
Initialization script '~/.gradle/init.gradle' line: 2
* What went wrong:
Could not compile initialization script '/Users/aloneitan/.gradle/init.gradle'.
> startup failed:
initialization script '~/.gradle/init.gradle': 2: Method definition not expected here. Please define the method at an appropriate place or perhaps try using a block/Closure instead. at line: 2 column: 5. File: _BuildScript_ # line 2, column 5.
def hi() {
^
1 error
It appears that the answer is that it is not possible to define a method to be used inside initscript using Groovy
It is worth noting that it is possible in Kotlin, though.

How to use regular expressions in gradle exec?

Since the Gradle integrated jacoco plugin cannot be used, there is a task skipped problem. I try to use Jacoco Command Line Interface and Exec - Gradle DSL Version 7.0.
def reportTask = tasks.create(reportTaskName, Exec.class) {
group = 'Reporting'
description = "Generate End To End Android Test Jacoco coverage reports on the ${buildVariant.capitalize()} build by Command Line Interface."
workingDir "${project.buildDir}"
commandLine "java", "-jar", "${jacocoCLI}", "report", "${project.buildDir}/outputs/code_coverage/${buildVariant}AndroidTest/connected/*.ec",
"--classfiles", "${project.buildDir}/intermediates/javac/${buildVariant}/classes/",
"--classfiles", "${project.buildDir}/tmp/kotlin-classes/${buildVariant}/",
"--html", "${project.buildDir}/jacocoReport/jacocoHtml/",
"--sourcefiles", "${project.projectDir}/src/main/java",
"--xml", "${project.buildDir}/jacocoReport/jacocoXml.xml"
}
reportTask
When I run this task, I get:
> Task :qtx:jacocoEtoeAndroidTestReportByCLI FAILED
[INFO] Loading execution data file <xxx>/build/outputs/code_coverage/etoeDebugAndroidTest/connected/*.ec.
Exception in thread "main" java.io.FileNotFoundException: <<xxx>>/build/outputs/code_coverage/etoeDebugAndroidTest/connected/*.ec (No such file or directory)
However, if I execute it in the terminal, as shown in the figure below, the task will succeed.
What's the difference between these two usages and how can I use Regular Expressions in Gradle Exec?
UPDATE
def _createAndroidTestCoverageReportByCLI(productFlavorName = "") {
def buildTypeName = "debug"
def buildVariant
buildVariant = "${productFlavorName}${buildTypeName.capitalize()}"
def getExecDataTaskName = "${ANDROID_TEST_REPORT_TASK_PREFIX}${productFlavorName.capitalize()}${ANDROID_TEST_REPORT_TASK_SUFFIX}ExecDataGetter"
def reportTaskName = "${ANDROID_TEST_REPORT_TASK_PREFIX}${productFlavorName.capitalize()}${ANDROID_TEST_REPORT_TASK_SUFFIX}ByCLI"
def jacocoCLI
String execData
project.rootProject.allprojects.each { project ->
if (project.name == "testlib") {
jacocoCLI = "${project.projectDir}/lib/jacococli.jar"
}
}
def getExecDataTask = tasks.create(getExecDataTaskName, JacocoReport.class) {
def listEc = []
def dir = new File("${project.buildDir}/outputs/code_coverage/${buildVariant}AndroidTest/connected/")
dir.eachFileRecurse() { file ->
listEc << file
}
execData = listEc.join(" ")
}
def reportTask = tasks.create(reportTaskName, Exec.class) {
group = 'Reporting'
description = "Generate End To End Android Test Jacoco coverage reports on the ${buildVariant.capitalize()} build by Command Line Interface."
workingDir "${project.buildDir}"
// commandLine "java", "-jar", "${jacocoCLI}", "report", "${execData}",
// "--classfiles", "${project.buildDir}/intermediates/javac/${buildVariant}/classes/",
// "--classfiles", "${project.buildDir}/tmp/kotlin-classes/${buildVariant}/",
// "--html", "${project.buildDir}/jacocoReport/jacocoHtml/",
// "--sourcefiles", "${project.projectDir}/src/main/java",
// "--xml", "${project.buildDir}/jacocoReport/jacocoXml.xml"
commandLine "java -jar ${jacocoCLI} report ${execData} --classfiles ${project.buildDir}/intermediates/javac/${buildVariant}/classes/ --classfiles ${project.buildDir}/tmp/kotlin-classes/${buildVariant}/ --html ${project.buildDir}/jacocoReport/jacocoHtml/ --sourcefiles ${project.projectDir}/src/main/java --xml ${project.buildDir}/jacocoReport/jacocoXml.xml"
}
reportTask.dependsOn getExecDataTask
}
Error
> Task :qtx:jacocoEtoeAndroidTestReportByCLI FAILED
Execution failed for task ':qtx:jacocoEtoeAndroidTestReportByCLI'.
> A problem occurred starting process 'command 'java -jar <RepoPath>/testlib/lib/jacococli.jar report <RepoPath>/QTX/build/outputs/code_coverage/etoeDebugAndroidTest/connected/spoon1619160691046.ec <RepoPath>/QTX/build/outputs/code_coverage/etoeDebugAndroidTest/connected/spoon1619161047292.ec <RepoPath>/QTX/build/outputs/code_coverage/etoeDebugAndroidTest/connected/spoon1619160787358.ec --classfiles <RepoPath>/QTX/build/intermediates/javac/etoeDebug/classes/ --classfiles <RepoPath>/QTX/build/tmp/kotlin-classes/etoeDebug/ --html <RepoPath>/QTX/build/jacocoReport/jacocoHtml/ --sourcefiles <RepoPath>/QTX/src/main/java --xml <RepoPath>/QTX/build/jacocoReport/jacocoXml.xml''
I tried to pass in execfiles through list, the task still failed. When I copied the failed command to the terminal for execution, it could be executed successfully.
Why? How can it be executed in Gradle?

Passing a gradle task arguments in command line

I'm trying to find the best way to pass a gradle task arguments from the command line.
I have this task. I want to unpack solutions from student exercises and copy them into the right place in the project to evaulate them. I call this task like this:
> gradle swapSolution -Pstudent=MyStudent -Pexercise=ex05
One Problem i have with this while doing this in IntelliJ while having the Gradle plugin enabled is that i get this error message when build the project. What could be a solution to this?
A problem occurred evaluating root project 'kprog-2020-ws'.
> Could not get unknown property 'student' for root project 'kprog-2020-ws' of type org.gradle.api.Project.
This is the gradle task:
task swapSolution(type: Copy) {
new File("${rootDir}/Abgaben").eachDir { file ->
if (file.name.toString().matches("(.*)" + project.property("student") + "(.*)")) {
def exDir = new File("/src/main/java/prog/" + project.property("exercise"))
if (!exDir.exists()) {
delete exDir
}
new File(file.path).eachFile { zipSolution ->
//def zipFile = new File("./Abgaben/" + file.name.toString() + "/" + project.property("exercise") + "Solution.zip")
from zipTree(zipSolution)
into "/src/main/java/"
}
}
}
}
Do you have any suggestions to optimize this process?
-P denotes the Gradle Project Property. If you need to use project properties you can specify it as a system property in gradle.properties file in project root directory.
If your task is of type JavaExec you can use --args switch and pass it in Arguments text field of the Gradle Task Run Configuration togenther with the task name like swapSolution -args="-student=MyStudent -exercise=ex05". See also
https://stackoverflow.com/a/48370451/2000323

How can I ask gradle for the value of a property from the command line?

For example, if I wanted a shell script to be able to get the value of rootProject.name, how could I do this? Ideally, I'd like to invoke ./gradlew with some set of arguments and have it print the property value (and nothing else) to stdout.
For clarity, here is my Gradle wrapper version:
$ ./gradlew --version
------------------------------------------------------------
Gradle 5.4.1
------------------------------------------------------------
Build time: 2019-04-26 08:14:42 UTC
Revision: 261d171646b36a6a28d5a19a69676cd098a4c19d
Kotlin: 1.3.21
Groovy: 2.5.4
Ant: Apache Ant(TM) version 1.9.13 compiled on July 10 2018
JVM: 11.0.2 (Oracle Corporation 11.0.2+9-LTS)
OS: Mac OS X 10.14.4 x86_64
This is an existing task to give you an idea of the properties available:
$ ./gradlew properties
> Task :properties
------------------------------------------------------------
Root project
------------------------------------------------------------
allprojects: [root project 'myProject', project ':otherProject', ...]
...
rootDir: /path/to/rootDir
rootProject: root project 'myProject'
...
version: 2.3.0
...
Here is a custom task I've built to print out a project property
class ResolveProperties extends DefaultTask {
#Input
String prop
ResolveProperties() {
// if no --prop=<property> is provided, default to spitting out all properties
prop = "properties"
}
#Option(option = 'prop', description = 'Set the property to be evaluated for the project.')
void setProp(final String prop) {
this.prop = prop
}
#TaskAction
void resolveProp() {
List<String> propPath = this.prop.tokenize('.')
int n = propPath.size()
def currentProp = project
propPath.eachWithIndex { p, i ->
if(currentProp.hasProperty(p)) {
currentProp = currentProp.property(p)
}
else {
throw new GradleException("failed to resolve property: ${this.prop}")
}
}
println "${this.prop} -> ${currentProp}"
}
}
task resolveProperties(type: ResolveProperties)
And this is how I use my custom task with a --prop parameter (indicated by #Option(option = 'prop'. I'm using the -q (quiet) Gradle option to suppress some of the extra output.
$ ./gradlew -q resolveProperties --prop=rootProject.name
rootProject.name -> onestop
resolveProperties took 0 seconds
$ ./gradlew -q resolveProperties --prop=rootProject.version
rootProject.version -> 2.3.0
resolveProperties took 0 seconds
$ ./gradlew -q resolveProperties --prop=rootProject.group
rootProject.group -> org.cedar.onestop
resolveProperties took 0 seconds
Because we are throwing a GradleException when we can't find the property, in Bash you can check the return code of the command to know when to parse out the value. The formatting of a successful output is up to you and you could make it easily parsed.
$ ./gradlew -q resolveProperties --prop=does.not.exist
resolveProperties took 0 seconds
FAILURE: Build failed with an exception.
* Where:
Build file '/Users/elliott/Documents/GitHub/onestop/build.gradle' line: 259
* What went wrong:
Execution failed for task ':resolveProperties'.
> failed to resolve property: does.not.exist
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 0s
In case of a failure like the one above, we get a non-zero return code in Bash, and we know we don't need to try and parse out the value:
$ echo $?
1
Unfortunately, I don't know a simple way in Gradle to only give the value you are concerned with to stdout (prevent some parsing), but this gets you most of the way there with some flexibility.
If it is still relevant ...
Possible Solution A: print value of "rootProject.name" on cmd line
Add task in build.gradle:
/**
* Prints value of property "rootProject.name" to stdout.
*
* Usage: ./gradlew -q printRootProjectName
*/
task printRootProjectName {
doLast {
println(project.findProperty('rootProject').name)
}
}
Possible Solution B: print a property value as provided on cmd line
Add task in build.gradle:
/**
* Print value of property provided in "-Pprop" on command line to stdout.
*
* Usage Example: ./gradlew -q printProperty -Pprop=rootProject.name
*/
task printProperty {
doLast {
// get the "property name" in question from commandline:
String prop = project.findProperty('prop')
if (prop == null) {
return // or use println ...
}
// treat as property name:
Object theProperty = project.findProperty(prop)
if (null == theProperty) {
// try to handle provided information as "nested property"
List < String > thePropPath = prop.split('\\.').toList()
theProperty = project.findProperty(thePropPath.head())
// aux. closure to travel "property path"
def pp = {
s,
t - >
if (s != null && s.hasProperty(t).is(true)) {
return s.property(t)
}
return null
}
thePropPath.tail().each {
item - >
theProperty = pp(theProperty, item)
}
}
println(theProperty ? : "") // or print "null" ...
}
}

How to execute a shell command for each file in a Gradle file collection?

I've recently been directed to implement all build/release engineering jobs in Gradle.
So I'm new to Gradle and some things which are drop-dead obvious at a shell prompt are just hard to fathom in this brave new world.
My build creates a set of jar files.
I need to execute a shell task for each one of them
Something similar to:
task findBugs (type:Exec, dependsOn: fb23) {commandLine 'java', '-jar',
'./findBugs/findbugs.jar', '-textui', '-progress', '-xml', '-output',
'TrustManagerService.xml', 'TrustManagerService.jar'}
(I can't usethe FindBugs plug-in because we're in JDK8 - so I'm running FindBugs externally from a preview version...)
I can get a file collection and iterate over the file names with something like:
FileTree iotTree = fileTree(dir: '.')
iotTree.include '*.jar'
iotTree.each {
File file -> println file.name
println 'A file'
}
or
def iotJars = files(file('./jars').listFiles())
println ''
println iotJars
iotJars.each { File file -> println 'The next file is: ' + file.name }
But for the life of me I can't see how to execute a shell command for each filename returned...
Thoughts on the most straightforward way to do this??
By the way - what's the best way to include the line breaks in the code listing - I had to return and add CRs to each line to get them to break...:(
You can use the execute method on a String to execute a shell command.
Here is an example task:
task executeExample << {
FileTree ioTree = fileTree(dir: ".")
ioTree.each { f ->
def proc = "ls -l ${f}".execute();
proc.waitFor();
println "return code: ${ proc.exitValue()}"
println "stderr: ${proc.err.text}"
println "stdout: ${proc.in.text}"
}
}

Resources