I am using a gradle task to generate some code for my API and store this code into the build folder. When I am building my application the process deletes the build folder.
Is there a way to call my code generation task between the folder deletion and the start of the compilation?
I am not a Gradle expert, so their might be better answers!
In your build.gradle you can create custom tasks and make them depend on other tasks:
// this is your new task
task generateCode() {
description 'Generates some code...'
doLast {
println("generateCode")
// do your code generation here
}
}
// put the name of the task you wanna depend on, like: compileSources
project.task("compileSources").dependsOn generateCode
When you call this task ./gradlew compileSources you should see that the custom task generateCode gets executed first.
After allot of trying , i found the solution .
In the build.gradle i had to add the preBuild.finalizedBy(generateCode)
Related
I am attempting to build a cache of APKs locally. The idea is that when you run any assemble type task, it will check locally for a previously built APK and move it into the build output folder.
I have made my own custom task that does this APK cache check. The signature is below:
tasks.register('apkCacheCheck') {
// checks for some criteria here
}
I have also made the assembleDebug task dependent on it:
tasks.whenTaskAdded{ task ->
if (task.name == "assembleDebug") {
task.dependsOn "apkCacheCheck"
task.enabled = foo // some output of apkCacheCheck
}
}
Problem:
When running assembleDebug to build an Android app, it will go up the graph and execute all its dependent tasks. However, I wanted to write a check that prevents the app from building anything until the check is finished. This way, we can save time by installing the cached APK rather than re-building it from scratch.
Questions:
Is there a way to stop all of the build tasks if said condition is met?
Is this a valid use case of Gradle or should I be looking towards running this as a Bash script?
In my gradle file I want to know which task triggered the code block. e.g. If I run
gradle assembleVanillaDebug
from the terminal, I want to know in my gradle file that assembleVanillaDebug task is being executed. This will also help me in figuring out I am running debug build type task or release build type task.
Can we know which task is being executed?
In the end,
gradle.startParameter.taskNames
proved to be my friend. gradle.startParameter.getTaskNames() would return you the list of all tasks being executed in current build.
e.g. For gradle clean assembleVanillaDebug, it will return you a list of tasks clean and assembleVanillaDebug.
Seeing this is still the first hit on google when you search for listing tasks, I thought I'd share the better way I found of getting all tasks that are being scheduled:
// Doc: Returns the tasks which are included in the execution plan.
// The tasks are returned in the order that they will be executed.
gradle.taskGraph.allTasks
As opposed to gradle.startParameter which is meant for finding out how gradle has been started, this gives you a list of actual task objects that gradle queues for execution.
Edit:
Make sure the graph is resolved before using it. It should be available when running a task action, for example in a doFirst {}, or try running your code in the whenReady{} closure like so:
project.gradle.taskGraph.whenReady {
println(project.gradle.taskGraph.allTasks)
}
I am trying to do a very simple thing. As gradle removes all files in the build dir when cleaning I want to move the apks somewhere else when creating release versions. So I added a copy task into the chain and I set it to be the last. Anything I tried did't work. So I simplified it and added some logging to make a point. I think it just doesn't work.
Using two variables, I can check that at task definition time and execution time the input and output paths are valid. I can also check that the task is executed. I put some more files in the input directory to make sure there is also something there in any case. This is the script:
def buildPath
def outPath
task copyApks(type: Copy) {
buildPath = "$buildDir\\outputs\\apk"
outPath ="$buildDir\\outputs\\apk2"
logger.error("Source Folder is $buildPath")
logger.error("Destination Folder is $outPath")
from buildPath
into outPath
}
assembleRelease.doLast {
android.applicationVariants.all { variant ->
println "Variant $variant.name"
logger.error("Source Folder is $buildPath")
logger.error("Destination Folder is $outPath")
copyApks
}
}
And this is the output, where one can see that the paths are correct (they exist and are valid) both at definition and execution time. Also one can see that the task is executed:
What is wrong?
Executing external task 'assembleRelease'...
Parallel execution with configuration on demand is an incubating feature.
Source Folder is C:\Users\Administrator\Projects\Gradle\MB6\app\build\outputs\apk
Destination Folder is C:\Users\Administrator\Projects\Gradle\MB6\app\build\outputs\apk2
................
some other gradle logs
................
:app:assembleRelease
Variant debug
Source Folder is C:\Users\Administrator\Projects\Gradle\MB6\app\build\outputs\apk
Destination Folder is C:\Users\Administrator\Projects\Gradle\MB6\app\build\outputs\apk2
Variant release
Source Folder is C:\Users\Administrator\Projects\Gradle\MB6\app\build\outputs\apk
Destination Folder is C:\Users\Administrator\Projects\Gradle\MB6\app\build\outputs\apk2
BUILD SUCCESSFUL
First of all, you have to know, that just adding the task name into your closure, in your case it's copyApks, doesn't really mean that this task should be executed. It's just the same, as you specified a variable, but do nothing with it.
And one more, note, the both variants paths are the same, that means that you are trying to copy tha same files twice. Actually, that not the only reason, you have to understand, that your copy task is configured yet in the configuration phase, when you are trying to call it during the execution phase, so you can't change it's from and into parameters, and this task will always behave the same.
If you want to call some tasks one after another, you have a number of choices, like task dependencies, task finalization or task ordering. You can read about it in the official user guide. There is a way to call some task like a method call, but this is a very poor solution and you have to avoid using it.
So, if you want to call a copy task, then you may try solution like this
assembleRelease.finalizedBy copyApks
This will call a copy task always every time assembling is done.
We have a gradle task that will automatically generate codes for us before building. See the following as an example,
task djinniTask(type: org.gradle.api.tasks.Exec) {
commandLine 'sh', './Djinni/run_djinni.sh'
}
assembleDebug.dependsOn djinniTask
Basically, the above run_djinni.sh is using a library djinni to generate JNI codes. The above works fine except that it will run this script every time we build even if we didn't update the script file, which is obviously not very efficient. We did a bit of research and found 17.9. Skipping tasks that are up-to-date. And as a result, the following works fine. It will skip this task if we didn't modify run_djinni.sh.
task transform {
ext.srcFile = file('./Djinni/run_djinni.sh')
ext.destDir = new File(buildDir, 'generated')
doLast {
commandLine 'sh', './Djinni/run_djinni.sh'
}
}
Now the problem is, the run_djinni.sh is not the only script file that we have. The project is big and we multiple scripts files like: run_foo_djinni.sh, run_bar_djinni.sh and etc. run_djinni.sh will call each of the other scripts. So is there a way to declare the inputs of a gradle task as multiple files, for example, in our case, every files that is under the Djinni folder?
Ok, according to gradle DSL you can define multiple inputs:
task transform {
inputs.files('file path', 'another file path')
}
I have 2 gradle tasks that i want to run after assembleRelease task.
task copyRequiredFilesToVersionControl(type:Copy) {
...
}
task ('versionControl') << {
...
}
If I configure order for these tasks as below tasks get never called...
copyRequiredFilesToVersionControl.dependsOn(assembleRelease)
versionControl.dependsOn(copyRequiredFilesToVersionControl)
If i change order like;
assembleRelease.dependsOn(copyRequiredFilesToVersionControl)
versionControl.dependsOn(copyRequiredFilesToVersionControl)
Tasks are run at the beginning of document. So there is no file to copy and add to version control.
What is the best approach?
I have found method that called doLast. So i fixed my problem with it.
assembleRelease {
doLast {
tasks.versionControl.execute()
}
}
The best approach that I've found to date, has been to use the Ordering Tasks feature in Gradle : see http://www.gradle.org/docs/current/userguide/more_about_tasks.html for more documentation, currently section 15.5.
Basically, you have two rules available : MUST run after and SHOULD run after. I like the rule quite a bit, I use this to create zip archives of projects automatically. NOTE : you must still make use of the "dependsOn" to get proper execution if tasks that you need to have run in a particular order.