any way to write more concise gradle? - 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!

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.

Call Zip Task Multiple Times In Gradle

I need to update 9 zip files and the code to do it is about 15 lines.
I'd rather not have to repeat the same 15 lines 9 times in the build script with just different variable names.
Is it possible to call a Zip task in a loop from another task?
Using dynamic tasks seems to be one way but it requires me to list the array of tasks twice which I can see causing an error in future when an extra item is added.
[war1, war2, war3, war4, war5, war6, war7, war8, war9].each { warName ->
task "task$warName"(type: Zip) {
archiveName = "${warName}.war"
//etc etc
}
}
task all(dependsOn: [taskwar1, taskwar2, taskwar3, taskwar4, taskwar5, taskwar6, taskwar7, taskwar8, taskwar9]) {
}
Is there any alternative?
Firs of all your code might be simplified just to:
task allWars
(1..9).each { id ->
task "taskwar${id}"(type: Zip) {
archiveName = "war${id}.war"
}
allWars.dependsOn "taskwar${id}"
}
And a solution with task rules:
tasks.addRule('Pattern: taskwar<ID>') { String taskName ->
if (taskName.startsWith('taskwar')) {
task(taskName, type: Zip) {
archiveName = "${taskName - 'task'}.war"
}
}
}
task allWars {
dependsOn << (1..9).collect { "taskwar$it" }
}
There are almost no obvious pros and cons - when it comes to functionality. Basically solution without rules is shorter as you can see, so if you represent attitude less code is better that's the way to go. However task rules were created in gradle for this kind of situations - where there are lots of predefined tasks. First solution is more groovier while the second one is more gradler ;)
One way is to store the list of 'war' names in a ext property and then iterate over it to create the tasks and use a mapping function for defining the dependencies for the all task.
// Define the variables here
ext.warTaskPrefix = "task"
ext.warNames = ["war1", "war2", "war3", "war4", "war5", "war6", "war7", "war8", "war9"]
// Define the war task dynamically
warNames.each { warName ->
task "${warTaskPrefix}${warName}"(type: Zip) {
archiveName = "${warName}.war"
//etc etc
}
}
// Define the task that depends on all war tasks
task all(dependsOn: warNames.collect{ warName -> "${warTaskPrefix}${warName}" }) {
}

How to reuse existing task in 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.

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