How to reuse existing task in Gradle - gradle

I have question how to reuse existing task in Gradle and what is recommended way?
I would like to change some properties of reused task.
I've found that it is possible to do in dependsOn or call execute, but is it recommended way? I've read that execute is not recommended. It looks like dependsOn is better way.
Example:
task task1() {
description = "task1"
doLast {
println description
}
}
task callModifiedTask1ByDependsOn() {
dependsOn {
task1 {
description = "modified task 1 by dependsOn"
}
}
}
task callModifiedTask1ByExecute() << {
project.task1 {
description = "modified task 1 by execute"
}.execute()
}

Hmm... Calling execute() explicitly seems not a good idea. Mind the fact that execute() method is part of internal API of Gradle so it can potentially change.
According to reusable task You can do it exactly the same as it's done in Gradle: e.g. copy task. Just implement the task and configure the part that is changed for execution (e.g. from). Your example with dependsOn follows this scenario more or less.

A task cannot be "reused", and cannot be called from another task (only depended upon). Instead, declare multiple tasks.

Related

Set the properties in the configuration phase of a task in another task

I have spent the last few hours trying to find a solution for my requirement, without luck:
I have a task that has to run some logic in a certain path:
task run(type: MyPlugin) {
pathForPlugin = myPath //Defined as a property in another gradle file
}
I want to set the "pathForPlugin" property dynamically in another task because it has to be read from some configuration file.
task initPaths(type: PathFinder) {
configurationFile = 'C:\\myConfig.conf'
}
The myConfig.conf would look like this:
pathForPlugin = 'C:\\Correct\\Path'
The problem is that "initPaths" has to run before the configuration phase of "run".
I have tried several approaches for this (GradleBuild task, dependsOn, Using Properties in the Plugin for "Lazy Configuration") but every approach only takes effect in the Execution phase leading to the "pathForPlugin" always staying at its default value.
Is there some way i can realize this or should i look for another solution outside of the gradle build?
I found a solution for the problem:
Instead of defining a task "initPaths" i directly used the java class "Pathfinder" in the build script:
import mypackage.PathFinder;
new PathFinder(project).run()
You only have to make sure that this part is above the definition of the task where the properties are used.
I admit this is a bit of a "hacky" solution but it works fine for my requirement.
you can do like this:
ext {
myPath //use it as a global variable that you can set and get from different gradle tasks and files
}
task firstTask {
doLast {
ext.myPath = "your path"
}
}
task run(type: MyPlugin) {
doFirst { //executed on runtime not on task definition
pathForPlugin = ext.myPath //Defined as a property in another gradle file
}
}
//example 2 - create run task dynamic
task initPath {
doLast {
tasks.create(name: "run", type: MyPlugin) {
pathForPlugin = ext.myPath
}
}
}

Gradle Sync task with doLast doesn't work

The gradle task is working well:
task mySync1(type: Sync) {
from "source-dir1"
from "source-dir2"
into "target-dir"
}
But if I add doLast, it doesn't nothing(and no errors):
task mySyncNotWorking(type: Sync) {
doLast {
from "source-dir1"
from "source-dir2"
into "target-dir-z"
}
}
The correct one is:
task mySyncFixed() {
doLast {
project.sync {
from "source-dir1"
from "source-dir2"
into "target-dir-z"
}
}
}
My question is the task mySyncNotWorking, the from and into methods are still belong to Sync if they are inside doLast? Why do they not work?
Why do they not work?
They do work, but after the task was executed. And you can't configure something after it was executed.
If you really need to configure your task during execution phase, maybe because you need to use the results of other tasks (but can't use task outputs for some reason), just use a doFirst closure.
The reason why nothing happens in your second example is the nothing-to-do check of the implemented task action. It is perfectly fine for a task to do nothing, this is not a reason for an error.

Gradle Task . "(type: Copy)" and <doLast> can't both work

task simpleTask{
print("simpleTask is reach");
}
task copySomeFile(type: Copy){
print("copySomeFile is reach");
from baseProjectPath;
into toProjectPath;
appendXML();
}
def appendXML(){
//modify a.txt
}
//i just want to run "simpleTask" only, but when "gradle simpleTask", the task"copySomeFile" will be run also ! I know beacuse gradle initialization.
but if write like this
task copySomeFile(type: Copy)<<{
}
the "copySomeFile" will not work.
it seems like "(type: Copy)" can't work with the "<<" or "doLast{}"?
i just want "--gradle simpleTask" "--gradle copySomeFile" can run alone.
You have to read about Gradle build lifecycle.
There are 2 phases you should note - Configuration and Execution. All tasks are always been configured on every build, but only some of them are really executed as the Execution phase.
What you see is that copySomeFile task was configured during the configuration phase. It doesn't copy anything, but it has to be configured. And everything within a tasks closure is task's configuration, that is why you see results of the print("copySomeFile is reach"); in the output.
<< or doLast are used to run something at the Execution phase, but your task of type Copy will not be configured if you place all it's configuration into doLast section or add << to the task definition - that is the reason why copy doesn't work.
Yeh, i got it. How much I appreciate both of you. SHARE THE CODE:
task simpleTask {
print("\nsimpleTask is configured"); // executed during the configuration plase, always
doLast {
print("\nsimpleTask is executed"); // executed during the execution plase, only if the simpleTask is executed
}
}
task copySomeFile(type: Copy) {
print("\ncopySomeFile is configured"); // executed always,执行其他任务时,此代码也会执行
from "D:/a.txt";// not executed. 执行其他任务时,此代码不会执行
into "D:/b.txt";// not executed. 执行其他任务时,此代码不会执行
doLast {
appendXML(); //only this task executed, the appendXML executed. 只有此task执行时,才会执行.比如(gradle copySomeFile);
}
}
def appendXML(){
print("\nappendXML");
}

any way to write more concise gradle?

I do not know groovy well enough yet and just trying to get by right now. I have the following gradle working right now but am wondering if there is a more concise way to write it:
task staging(type: Sync) {
from(stagingDir) {}
into toStagingDir
}
task syncJars(type: Sync) {
from(configurations.compile) {}
from(fixedLibDir) {}
into toStagingLibsDir
}
task copyMainJar(type: Copy) {
from(libsDir) {}
into toStagingLibsDir
}
task myZip(type: Zip) {
archiveName "bacnet.zip"
from(buildDir) {
include project.name+'/**'
}
}
syncJars.dependsOn('staging')
copyMainJar.dependsOn('syncJars')
myZip.dependsOn('copyMainJar')
assemble.dependsOn('myZip')
Perhaps there is someway to write it like this:
task prepareStaging {
staging from stagingDir into toStagingDir
syncJars from configurations.compile from fixedLibDir into toStagingLibsDir
copyMainJar from libsDir into toStagingLibsDir
myZip archiveName "bacnet.zip" from buildDir { include project.name+'/**' }
}
assemble.dependsOn('prepareStaging')
Ideally, I LOVE self-documenting code. In this second example, it is obvious to the next developer I mean each of those small tasks to NOT be re-usable. This is very clear(ie. self-documenting). In the first way I wrote the code that is definitely not clear as those tasks could be re-used from other project files.
Any way to write it in that simpler form?
NOTE: I still want all the UP-TO-DATE checks to happen as well as usual though!!!
If I understood correctly, and toStagingDir and toStagingLibDir are just temporary directories that are created under the buildDir directory (in myZip task), then below should do an equivalent job to yours:
task myZip(type: Zip){
archiveName "bacnet.zip"
into('staging'){
from stagingDir
}
into('staging/libs'){
from fixedLibDir
from configurations.compile
from libsDir
//or this, if you just want to include current projects jars
from jar.outputs.files
}
}
The idea here is not to create a temporary directory yourself, but let gradle do it for you.
As long as you dont call cleanMyZip it will do UP-TO-DATE checks and do the bare minimum. Last time I checked Zip behaved much like Sync, in that it would remove any files from the zip that are no longer present in the source. This may behave slightly differently to copyMainJar task, because it's of type Copy which means if you ever delete a file from libsDir then in my case it would disappear from the zip, but in your code it will not.
Don't know if this is even close to what you're asking, but hope it's at least of a little use:)
Elaboration:
Tasks in gradle are always public by design AFAIK. There is an enhancement request but without much action around it. You can use standard groovy methods, which support private visibility, but they aren't as powerful as tasks. Although, you'll find that tasks can depend on groovy functions and more (or anything with call() method), so you can do stuff like:
def function = {
println "function here!"
}
task myTask(dependsOn: function) << {
println "myTask here!"
}
will generate:
function here!
:a:myTask
myTask here!
This should give you some flexibility, but if you really really really need an private task you can do some dirty hacking (I know Gradle guys will hate me for this xx;) ... here it is:
//Create a factory for creating tasks
import org.gradle.api.internal.project.taskfactory.ITaskFactory
def taskFactory = project.services.get(ITaskFactory)
//You can use the factory to create tasks without adding them to
//project.tasks, which will make them invisible to most irrelevant
//parts of your code, and they will not come up in `gradle tasks` list:
//Equivalent of:
// task myTask << {
// println "i'm invisible"
// }
def privateTask = taskFactory.createTask([name: 'myTask']).doLast {
println "i'm invisible"
}
//Equivalent of:
// task myCopyTask(type: Copy){
// from configurations.compile
// into 'libs'
// }
def privateCopyTask = taskFactory.createTask([name: 'myCopyTask', type: Copy])
.configure {
from configurations.compile
into 'lib-test'
}
//You can depend on the above tasks as usual from your public tasks:
task publicTask(dependsOn: [privateTask, privateCopyTask]) << {
println "I'm public task"
}
Note: Seems to work in Gradle 1.2, but use at your own risk!
Good luck!

Moving built-in gradle tasks work to doLast/built-in tasks shourtcuts

I want to create a simple sync task that slightly change it behaviour depending on build type (e.g. debug/release) and I use boolean variable 'dummy' decrared in gradle.taskGraph.whenReady:
gradle.taskGraph.whenReady {taskGraph ->
dummy = false
if (taskGraph.hasTask(':dummybuild')) {
dummy = true
}
}
The problem is that task configured by the following way has configuration scope, i.e. before whenReady so it doesn't have access to the 'dummy' variable:
task copySkins(type: Sync) {
from skinsFrom
into skinsInto
rename skinsRename
exclude symbianExclude
if (!dummy) exclude dummyExclude
}
Right now I'm using this workaround
task copySkins {
inputs.dir skinsFrom
outputs.dir skinsInto
doLast {
task skins(type: Sync) {
from skinsFrom
into skinsInto
rename skinsRename
exclude symbianExclude
if (!dummy) exclude dummyExclude
}
skins.execute()
}
}
Is it possible to
detect/setup some build properties in some other place except whenReady
move sync task work to doLast
or at least have some shortcut for sync task (.execute() looks quite ugly)
1) whenReady event allows user to access fully-initialized task graph: all initialization is finished and tasks are ready to run. The only situation, when you need to detect/setup build properties here, is when you need to introspect current build setup.
If you do not need this information, you can place your initialization anywhere in your build script. At the very end, it is nothing but groovy script.
apply plugin: 'java'
def now = new Date()
compileJava.doFirst {
println "It is ${now}. We are starting to compile"
}
2) You can not move sync task work to doLast. But you can always add your actions to doFirst ;) I think, this should work:
task copySkins(type: Sync) {
from skinsFrom
into skinsInto
rename skinsRename
exclude symbianExclude
doFirst {
if (!dummy) exclude dummyExclude
}
}
3) With all said before, missing sync task shortcut should not be that painfull

Resources