Null dependency in gradle? (workaround for lazy downloads?) - gradle

I would like to be able to write something like this:
dependencies {
myConfig computeMyDependency()
}
and I want to be able to say "there is no dependency". Returning null or an empty map doesn't work. I suppose I can return files('/dev/null'), but that is weird, hacky and not portable. Is there some sort of null dependency constructor I can use?
Some background:
What I'm really trying to do is to defer dependency download to actual execution time. It appears that if a write a task, for example a copy task like so:
task copyMyDependencyFile(type: Copy) {
from { configurations.myConfig
.grep { it.name.endsWith("zip") }
.collect() { zipTree it }
}
into targetDir
}
Then running ./gradlew tasks will actually execute the from closure, which makes me very sad. (Using Gradle 2.4)

A quick workaround might be also:
task copyMyDependencyFile << {
copy {
from {
configurations.
compile.
grep { it.name.endsWith("jar") }.
collect { zipTree it }
}
into targetDir
}
}
It should be portable.
Not sure but maybe from and into maybe configured in doLast closure of task with type Copy:
task copyMyDependencyFile(type: Copy) {
doLast {
from {
configurations.
compile.
grep { it.name.endsWith("jar") }.
collect { zipTree it }
}
into targetDir
}
}
Please try the latter yourself.

Related

Gradle : use a task to disable another task

I have three gradle tasks (this is kotlin code inside a plugin):
project.task<Task>("checkNeeded") {
doLast {
if (someTest()) {
listOf("SomeCopy", "SomeAction")
.map { project.tasks[it] as AbstractTask }
.forEach { it.isEnabled = false }
}
}
}
project.task<Copy>("SomeCopy") {
dependsOn("checkNeeded")
from(wherever)
into(whatever)
}
project.task<Task>("SomeAction") {
dependsOn("checkNeeded")
doLast {
/* something magical */
}
}
So, both tasks SomeCopy and someAction depend on checkNeeded. The role of checkNeeded is to disable these two task if it finds that they are not needed.
However, this crashes with the following exception: Cannot call Task.setEnabled(boolean) on task ':SomeCopy' after task has started execution.
So, how can I have a task guaranteed to run before other tasks that can disable other tasks if they are not needed?
I ended up fixing this issue with onlyIf:
var needed by Delegates.notNull<Boolean>()
project.task<Task>("checkNeeded") {
doLast {
needed = !someTest()
}
}
project.task<Copy>("SomeCopy") {
dependsOn("checkNeeded")
onlyIf { needed }
from(wherever)
into(whatever)
}
project.task<Task>("SomeAction") {
dependsOn("checkNeeded")
onlyIf { needed }
doLast {
/* something magical */
}
}
Note that the checkNeeded task is not really necessary, but I like to have it to know, in the process, when the check is made. I could have done:
val needed by lazy { !someTest() }
project.task<Copy>("SomeCopy") {
onlyIf { needed }
from(wherever)
into(whatever)
}
project.task<Task>("SomeAction") {
onlyIf { needed }
doLast {
/* something magical */
}
}
The dependsOn does set the order. It may make sense to move the if outside the checkNeeded task and place it either in the build script (it will be executed in the configuration phase) or in the afterEvaluate {...} block (it will still be executed in the configuration phase, but later)
Another option is to execute checkNeeded task explicitly before running one of the SomeCopy or SomeAction

How to find `type` of Gradle task?

I have the following code which works fine:
allprojects {
tasks.whenTaskAdded { task ->
if (task.name =~ /generate.*Proto/) { // ①
task.dependsOn(protolockStatus)
task.finalizedBy(protolockCommit)
}
}
}
Rather than assuming some task naming convention on the line commented with ①, I'd like to make the condition based on the type of the task. I had thought type instanceof would work, but it did not. I also don't see any methods that would provide the type of the task. Is there a way to do this?
You could use the class of the task for that. So for example, you could try this:
allprojects {
tasks.whenTaskAdded { task ->
println "Type is " + task.class.simpleName
}
}

Gradle Copy Task Is UP-TO-DATE After Manually Deleting a File

I am forced to use Gradle 2.3 in this project.
I am trying to copy a set of dependencies from a custom configuration to a specific dir.
If I delete one of the files manually, Gradle still marks the task as UP-TO-DATE and I end up with an incomplete set of files.
task copyFiles(type: Copy) {
from configurations.zips
into 'zip-dir'
configurations.zips.allDependencies.each {
rename "-${it.version}", ''
}
}
This works as expected in v4.0.2 though.
To work around it I am counting files in that dir.
task copyFiles(type: Copy) {
outputs.upToDateWhen {
def count = new File('zip-dir').listFiles().count { it.name ==~ /.*zip/ }
count == configurations.zips.files.size()
}
from configurations.zips
into 'zip-dir'
configurations.zips.allDependencies.each {
rename "-${it.version}", ''
}
}
Which issue and version of gradle was this fixed in and is there a better workaround than what I have so far?
You can just run it always with
outputs.upToDateWhen { false }
or not use a type Copy for your task and
task copyFiles {
doLast {
copy {
from configurations.zips
into 'zip-dir'
configurations.zips.allDependencies.each {
rename "-${it.version}", ''
}
}
}
}
Note that this is a workaround not the solution

How do I alias gradle task as if it were called with -x parameter?

I want instead of gradle cleanIdea idea -x compileJava -x compileTestJava
call something like gradle ideaNoRecompile
You can use TaskExecutionGraph to do it. First of all, you need to provide a custom task, named ideaNoRecompile, when during the configuration phase, you need to check, whether this graph contains ideaNoRecompile task (that means, that this task will be executed. And if this task should be executed, then you can use a closгre to skip all the tasks, you don't want to be executed. Something like this:
task ideaNoRecompile(dependsOn:idea) {
gradle.taskGraph.whenReady { graph ->
if (graph.hasTask(ideaNoRecompile)) {
compileJava.enabled = false
compileTestJava.enabled = false
}
}
}
I've found another similar answer:
task ideaNoRecompile {
finalizedBy allprojects*.tasks*.idea
doFirst {
def skipTasks = ['compileJava', 'compileMirah', 'processResources', 'classes', 'compileTestJava', 'compileTestMirah', 'processTestResources', 'testClasses', 'jar', 'mergeProperties', 'generateModuleManifest' ] as Set
allprojects*.tasks*.each {
if (skipTasks.contains(it.name))
it.enabled = false
}
}
}

Communication between gradle methods and tasks

I can't seem to get my collection from the method to a state where generateWadleTasks can iterate over it. At least not in a way such that I can access it. I've tried properties, parameters and return values. What's wrong with this picture? I seem to have some misconceptions about how information is passed around either in Groovy or in Gradle... or perhaps both. An explanation of the scopes involved might help. This is a subproject.
buildscript{
...
}
ext.collectionOfObjects = []
class WadleProfile {
def File wadleFile;
def wadlArgs;
}
ext.factoryMethod = {
//supposed to create and add WadleProfiles to collectionOfWadleProfiles
}
compileJava {
doFirst { factoryMethod() }
}
task generateWadlTasks {
println "Executing generateWadlTasks"
project.ext.collectionOfObjects.each { wadlProfile ->
task("wadl2java" + wadlProfile.id, type: JavaExec, dependsOn: 'classes') {
main = project.wadlBaseMain
...
}
}
}

Resources