What is the proper way to refer to resource directory path in one source set in gradle? - gradle

In my build.gradle file, I have defined a separate sourceSet for integration tests:
sourceSets {
integtest {
java.srcDir 'src/integtest/java/io/attil/integration'
resources.srcDir 'src/integtest/resources'
}
}
I would like to use the path to resources of the integration tests in one of my manually defined tasks (a task that prefills the data-base for integration tests; the sql script is located in the mentioned resource folder).
I have now the following solution:
task prefillDatabase {
// ... snip!
String sqlString = new File(sourceSets.integtest.resources.srcDirs.iterator().next().toString() + '/setup_integration_tests.sql').text
// ... snip!
}
While this works, it is quite cumbersome.
Is there a better, shorter way to achieve the same? (I'm looking for something like sourceSets.integtest.resources.srcDir.)

I'm not sure this is less verbose, but I'd argue it's more correct
File file = sourceSets.integtest.resources.matching {
include 'setup_integration_tests.sql'
}.singleFile
String sqlString = file.text
See FileTree.matching(Closure) and FileCollection.getSingleFile()
Also, this looks wrong to me
java.srcDir 'src/integtest/java/io/attil/integration'
I'd think it would be
java.srcDir 'src/integtest/java'
java.include 'io/attil/integration/**'

Related

Is there a way to access variables from an imported gradle script?

I have a build.gradle file that's fairly long, and I'd like to break some of the logic up into smaller files to make the whole thing more maintainable. After moving some tasks into a new file, I found that none of the variables I had set in the parent script were available in the child script. Below is a pair of source files I reproduced this behavior with:
build.gradle:
apply from: 'repro.gradle'
def foo = "This is a variable"
tasks.register('printFromMainScript') {
println(foo)
}
repro.gradle:
tasks.register('printFromChildScript') {
println(foo)
}
In the above example, printFromMainScript works fine, but printFromChildScript fails. Is there a way to access foo from repro.gradle?
def foo creates a variable that exists only in the scope of build.gradle. Gradle documentation explains this more in detail.
There is ext block in Gradle which is meant for extra properties.
This should work in your case:
build.gradle:
apply from: 'repro.gradle'
ext {
foo = "This is a variable"
}
repro.gradle:
task printFromChildScript {
doLast {
println(project.foo)
}
}
Note: doLast block ensures that the println function is called only when the project is fully configured and printFromChildScript is actually executed. If you put println directly in task body then it will be executed during Gradle project configuration phase.

Calling the same task multiple times in a single build.gradle file

I have a custom Gradle plugin that will generate Java files from a template file. I have several such template files in different locations, and I need to "compile" all of them to generate the Java files I need. Once I have the files, I want to package them into a .jar.
One way I thought I could do this was to call the "compile template" task multiple times from within the same build file. I'd call it once in a task that compiles template files in location A, again from a task that compiles template files from location B... etc., until I have all the Java files I need.
Something like this:
task compileFromLocationA <<{
compileTemplate.execute(A)...
}
task compileFromLocationB
compileTemplate.execute(B)...
...
packageJar(depends: compileFromLocationA, compileFromLocationB, ...)
...
However, you can't programmatically call a task from within another task. I suppose I could break each compileFromLocation_ task into it's own build.gradle file, but that seems like overkill. What's the "best practice" in a case like this?
This code seems to work in build.gradle by using tasks.register() - e.g. to perform multiple source code generating steps - in my case I needed to load different pairs of files (XML schema and generation options) in two different steps:
plugins {
id 'java'
id "com.plugin" version "1.0"
}
sourceSets.main.java.srcDirs += file("${buildDir}/genSrc")
sourceSets.test.java.srcDirs += file("${buildDir}/testGenSrc")
tasks.compileJava {
dependsOn tasks.named("genMessage")
}
genMessage {
codesFile = "${projectDir}/src/main/resources/file.xml"
}
def testGenModel1 = tasks.register("testGenModel1", com.plugin.TestGenModelTask.class) {
schema = "${projectDir}/src/test/resources/file.xsd"
options = "${projectDir}/src/test/resources/file.xml"
}
def testGenModel2 = tasks.register("testGenModel2", com.plugin.TestGenModelTask.class) {
schema = "${projectDir}/src/test/resources/file2.xsd"
options = "${projectDir}/src/test/resources/file2.xml"
}
tasks.compileTestJava {
dependsOn tasks.named("testGenModel1"), tasks.named("testGenModel2")
}

include not found copySpec / Sync task Gradle

I'm trying to sync specific files from a dir with Gradle. But I get a odd error that I can't seem to solve. If there is a better (working) way to filter files while syncing that would also be welcome.
Implementation 1
def updateAbstractsContentSpec = copySpec {
from('../../base') {
includes "../../base/shared/**/*_abstract.*"
}
}
task updateAbstracts(type: Sync) {
group 'build'
with updateAbstractsContentSpec
}
Error 1
Error:(24, 0) Could not find method includes() for arguments [../../base/shared/**/*_abstract.*] on object of type org.gradle.api.internal.file.copy.CopySpecWrapper_Decorated.
Implementation 2 (Preferable)
task updateAbstracts(type: Sync) {
group 'build'
from '../../base'
includes '../../base/shared/**/*_abstract.*'
}
Error 2
Error:(23, 0) Could not find method includes() for arguments [../../base/shared/**/*_abstract.*] on task ':apps:TestApp1:updateAbstracts' of type org.gradle.api.tasks.Sync.
I assume that its clear what I try to do. I hope that somebody can help me with this.
As of Gradle 3.0 CopySpec documentation, CopySpec does not contain includes method.
You should use include instead:
task updateAbstracts(type: Sync) {
group 'build'
from '../../base'
include '../../base/shared/**/*_abstract.*'
}

Reading includes from idl file in custom task

I want to make my gradle build inteligent when building my model.
To acquire this I was planning to read schema files, acquire what is included and then build firstly included models (if they are not present).
I'm pretty new to Groovy and Gradle, so please that into account.
What I have:
build.gradle file on root directory, including n subdirectories (subprojects added to settings.gradle). I have only one gradle build file, because I defined tasks like:
subprojects {
task init
task includeDependencies(type: checkDependencies)
task build
task dist
(...)
}
I will return to checkDependencies shortly.
Schema files located externally, which I can see.
Each of them have from 0 to 3 lines of code, that say about dependencies and looks like that:
#include "ModelDir/ModelName.idl"
In my build.gradle I created task that should open, and read those dependencies, preferably return them:
class parsingIDL extends DefaultTask{
String idlFileName="*def file name*"
def regex = ~/#include .*\/(\w*).idl/
#Task Action
def checkDependencies(){
File idlFile= new File(idlFileName)
if(!idlFile.exists()){
logger.error("File not found)
} else {
idlFile.eachLine{ line ->
def dep = []
def matcher = regex.matcher(line)
(...)*
}
}
}
}
What should I have in (...)* to find all dependencies and how should I define, that for example
subprojectA::build.dependsOn([subprojectB::dist, subprojectC::dist])?
All I could find on internet created dep, that outputted given:
[]
[]
[modelName]
[]
[]
(...)

Gradle with Eclipse - incomplete .classpath when multiple sourcesets

I have a gradle build script with a handful of source sets that all have various dependencies defined (some common, some not), and I'm trying to use the Eclipse plugin to let Gradle generate .project and .classpath files for Eclipse, but I can't figure out how to get all the dependency entries into .classpath; for some reason, quite few of the external dependencies are actually added to .classpath, and as a result the Eclipse build fails with 1400 errors (building with gradle works fine).
I've defined my source sets like so:
sourceSets {
setOne
setTwo {
compileClasspath += setOne.runtimeClasspath
}
test {
compileClasspath += setOne.runtimeClasspath
compileClasspath += setTwo.runtimeClasspath
}
}
dependencies {
setOne 'external:dependency:1.0'
setTwo 'other:dependency:2.0'
}
Since I'm not using the main source-set, I thought this might have something to do with it, so I added
sourceSets.each { ss ->
sourceSets.main {
compileClasspath += ss.runtimeClasspath
}
}
but that didn't help.
I haven't been able to figure out any common properties of the libraries that are included, or of those that are not, but I can't find anything that I'm sure of (although of course there has to be something). I have a feeling that all included libraries are dependencies of the test source-set, either directly or indirectly, but I haven't been able to verify that more than noting that all of test's dependencies are there.
How do I ensure that the dependencies of all source-sets are put in .classpath?
This was solved in a way that was closely related to a similar question I asked yesterday:
// Create a list of all the configuration names for my source sets
def ssConfigNames = sourceSets.findAll { ss -> ss.name != "main" }.collect { ss -> "${ss.name}Compile".toString() }
// Find configurations matching those of my source sets
configurations.findAll { conf -> "${conf.name}".toString() in ssConfigNames }.each { conf ->
// Add matching configurations to Eclipse classpath
eclipse.classpath {
plusConfigurations += conf
}
}
Update:
I also asked the same question in the Gradle forums, and got an even better solution:
eclipseClasspath.plusConfigurations = configurations.findAll { it.name.endsWith("Runtime") }
It is not as precise, in that it adds other stuff than just the things from my source sets, but it guarantees that it will work. And it's much easier on the eyes =)
I agree with Tomas Lycken, it is better to use second option, but might need small correction:
eclipse.classpath.plusConfigurations = configurations.findAll { it.name.endsWith("Runtime") }
This is what worked for me with Gradle 2.2.1:
eclipse.classpath.plusConfigurations = [configurations.compile]

Resources