How to make tasks execute one after another? - java

Basically I have 4 tasks that I need to run sequentially, but I cannot make them do so, I have to run it one by one on the command line as so:
gradle :drmdexsecondary:compileReleaseJava --info --debug --stacktrace
gradle :drmdexsecondary:dexClasses --info --debug --stacktrace
gradle :drmdexsecondary:jar --info --debug --stacktrace
Here's my build.gradle:
evaluationDependsOnChildren();
task dexClasses( type:Exec ) {
// compileJava.execute()
String cmdExt = Os.isFamily(Os.FAMILY_WINDOWS) ? '.bat' : ''
println("${buildDir}")
println("${androidSdkDir}\\build-tools\\${buildToolsVersion}\\dx${cmdExt} --dex --output=${buildDir}\\classes\\classes.dex ${buildDir}\\classes\\release")
commandLine "cmd", "/c", "${androidSdkDir}\\build-tools\\${buildToolsVersion}\\dx${cmdExt} --dex --output=${buildDir}\\classes\\classes.dex ${buildDir}\\classes\\release"
}
task jar(type: Jar) {
from ("${buildDir}\\classes\\classes.dex")
}
My problem is this:
the dependsOn keyword doesn't work... it just get ignored without any log message
taskname.execute() function doesn't work... it just get ignored without any log message
compileReleaseJava is not recognized inside build.gradle with this particular error: Could not find property 'compileJava' on task ':drmdexsecondary:dexClasses'.
Would anyone please help?
I've consulted and copy paste from the documentation but none of them seems work. I've even tried to re-install Gradle... there is so few sample codes there and although I understand the concept, it seems so difficult to translate my intention into working Gradle code, so if there is any good resources to help, it will be very appreciated as well.

You should read about gradle tasks and more about tasks. You want to depend on things rather then invoke things.
Also I think you should read about, and use the gradle android plugin.
To your original question, when you define a task the code between the braces is run at configuration time. A task's actions are run when the task is executed and must be added to the task's action list. This is done by using the task's doFirst, doLast or the << operator.
Here is an example from the gradle documentation.
task taskX << {
println 'taskX'
}
task taskY << {
println 'taskY'
}
task taskZ << {
println 'taskZ'
}
taskX.dependsOn taskY
taskY.dependsOn taskZ
taskZ.shouldRunAfter taskX

task1.finalizedBy task2 will run task2 after task1.

The Best Answer is Here
task myTask1() {
println("this is task1 running")
}
task task2() { dependsOn myTask1
println("this is task2 running")
}
when you execute gradle task2 .
this wil first execute task1 ,and then execute task2
you should use dependsOn key words
For example
task buildMyApk(type: Exec) {
def myCommond = ['gradle', "assembleRelease"]
commandLine myCommond
}
task moveApkFileToProjectFolder() { dependsOn buildMyApk
def releaseApkFilePath = "${buildDir}/outputs/apk/release/"
def targetApkFolder = "${rootProject.getProjectDir()}/apkFolder"
mkdir "${targetApkFolder}"
copy{
from releaseApkFilePath
into targetApkFolder
}
}
above answer will not work
task moveApkFileToProjectFolder run ,will first run buildMyApk.
my example task ,first will build apks .and then move apk File to my Project/apkFile folder .and execute success.

You can create a task of type GradleBuild and define the tasks inside of that task.
task releaseAfterMath(type: GradleBuild) {
tasks = [
'clean',
'build',
'publish',
'publishToMavenLocal',
'commitNewVersionTask',
'gitChangelogTask',
'commitChangelogTask'
]
}
And you can trigger releaseAfterMath like any other task. Running code here:
https://github.com/tomasbjerre/gradle-scripts/

For sequential or whatever the sequence you want to run your tasks, I do the following thing in my build.gradle file:
def modules = ["X", "Y", "Z", "ZZ"]
if (modules.size() > 1) {
for(j in 1 .. modules.size()-1 ) {
tasks[modules[j]].mustRunAfter modules[values[j-1]]
}
}

Related

Configure plugin from custom task [duplicate]

I'm using Gradle. I have two tasks: "a" and "b". I want task "a" to call task "b". How can I do this?
task b(type: Exec) {
description "Task B"
commandLine 'echo', 'task-b'
}
task a(type: Exec) {
description "Task A"
commandLine 'echo', 'task-a'
// TODO: run task b
}
In Ant this is a piece of cake:
<target name="a">
<echo message="task-a"/>
<antcall target="b"/>
</target>
<target name="b">
<echo message="task-b"/>
</target>
The first method I tried is using the "dependsOn" feature. However this is not ideal as we would need to think of all the tasks in reverse and also has several other issues (like running a task when a condition is satisfied).
Another method I tried is:
b.mustRunAfter(a)
However this only works if I run the gradle tasks like so:
gradle -q a b
Which is also not ideal.
Is there anyway to simply just call another task from an existing task?
As suggested one method would be to add a finalizer for the task
task beta << {
println 'Hello from beta'
}
task alpha << {
println "Hello from alpha"
}
// some condition
if (project.hasProperty("doBeta")) {
alpha.finalizedBy beta
}
Then we can execute the other task if needed. As for executing tasks from another tasks you cannot do that. Task declaration is declarative not imperative. So a task can depend on another task but they cannot execute another task.
$ gradle -q alpha
Hello from alpha
$ gradle -q alpha -PdoBeta
Hello from alpha
Hello from beta
You can use
a.dependsOn 'b'
Or
a.dependsOn b
Or
task a(type: Exec, dependsOn: 'b') { ... }
etc
See adding dependencies to tasks
To summarize and combine the answers from #JBirdVegas and #lance-java, using non-deprecated doLast instead of leftShift (<<):
task beta {
doLast {
println 'Hello from beta'
}
}
task alpha {
doLast {
println 'Hello from alpha'
}
}
// some condition
if (project.hasProperty('doBeta')) {
alpha.finalizedBy beta // run 'beta' after 'alpha'
// or
// alpha.dependsOn beta // run 'beta' before 'alpha'
}
It is working fine but providing a warning as Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0.
I am using gradle version 4.7. So it means some of the features you have added in the build.gradle will not work as it is in gradle 5.0.
Run the Gradle build with a command line argument --warning-mode=all to see what exactly the deprecated features are.
It will give you a detailed description of found issues with links to the Gradle docs for instructions how to fix your build.

Gradle unable to write sysout to file - java.io.IOException: Unable to delete file

I am trying to put output of a command to some file. Before writing the file i want to delete the file and than do write operation. Here is my gradle script
group 'org.example'
version '1.0-SNAPSHOT'
task deletefiles(type: Delete){
delete "$projectDir/somefile.txt"
}
task writefile(type: Exec, dependsOn: deletefiles){
commandLine 'echo', "Hello World"
standardOutput = new FileOutputStream("$projectDir/somefile.txt")
}
But when i run writefile tasks , I get below error
Execution failed for task ':deletefiles'.
> java.io.IOException: Unable to delete file 'D:\workspace\code\repo\sample-gradle-mono\somefile.txt'
Any idea what's wrong?
One thing i guess is that gradle is somehow acquiring lock on file before deletefiles tasks could start. If that is the case, How can we achieve this?
Edit 1:
Enviroment info -
------------------------------------------------------------
Gradle 6.3
------------------------------------------------------------
Build time: 2020-03-24 19:52:07 UTC
Revision: bacd40b727b0130eeac8855ae3f9fd9a0b207c60
Kotlin: 1.3.70
Groovy: 2.5.10
Ant: Apache Ant(TM) version 1.10.7 compiled on September 1 2019
JVM: 11.0.4 (Oracle Corporation 11.0.4+11)
OS: Windows 10 10.0 amd64
the problem that in your gradle the following line executed at project configuration phase
standardOutput = new FileOutputStream("$projectDir/somefile.txt")
it means that stream is created and file locked even before any gradle task was started..
try this groovy configuration to see the issue:
class MyStream extends FileOutputStream{
MyStream(String f){
super(f)
println "write $f stream created"
}
}
task deletefiles(type: Delete){
println "delete init"
doFirst{
println "delete doFirst" //triggered just before deletion
}
delete "out.txt"
}
task writefile(type: Exec, dependsOn: deletefiles){
println "write init"
commandLine 'cmd', '/C', 'echo', "Hello World"
standardOutput = new MyStream("out.txt")
}
in output you can see that stream is created before tasks execution:
cmd> gradle writeFile
> Configure project :
delete init
write init
write out.txt stream created
> Task :deletefiles FAILED
delete doFirst
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':deletefiles'.
> java.io.IOException: Unable to delete file 'out.txt'
To fix it - define the standardOutput just before the "Exec" task is executed:
class MyStream extends FileOutputStream{
MyStream(String f){
super(f)
println "write $f stream created"
}
}
task deletefiles(type: Delete){
println "delete init"
doFirst{
println "delete doFirst"
}
delete "out.txt"
}
task writefile(type: Exec, dependsOn: deletefiles){
println "write init"
commandLine 'cmd', '/C', 'echo', "Hello World"
doFirst{
println "write doFirst"
standardOutput = new MyStream("out.txt")
}
doLast{
println "write doLast"
}
}
output:
cmd>gradle writeFile
> Configure project :
delete init
write init
> Task :deletefiles
delete doFirst
> Task :writefile
write doFirst
write out.txt stream created
write doLast
BUILD SUCCESSFUL in 3s
2 actionable tasks: 2 executed
to add some clarity:
for example the this task definition
task writefile(type: Exec, dependsOn: deletefiles){
println "write init"
commandLine 'cmd', '/C', 'echo', "Hello World"
doFirst{
println "write doFirst"
standardOutput = new MyStream("out.txt")
}
doLast{
println "write doLast"
}
}
you could replace with the following groovy code in your gradle:
def writefile = project.task( [type: Exec, dependsOn: deletefiles], 'writeFile' )
println "write init"
writefile.setCommandLine( ['cmd', '/C', 'echo', "Hello World"] )
writefile.getActions().add( 0, {
//those commands will be executed later when task `writefile` decided to be executed by gradle
println "write doFirst"
writefile.standardOutput = new FileOutputStream("out.txt")
} as Action)
writefile.getActions().add( {
//those commands will be executed later when task `writefile` decided to be executed by gradle
println "write doLast"
} as Action)
links to official documentation that could explain this behavior:
https://docs.gradle.org/current/userguide/build_lifecycle.html#sec:settings_file
https://docs.gradle.org/current/userguide/more_about_tasks.html
It is possible that something is holding the file open. Sometimes if IO streams are not properly closed this can happen. Gradle docs say that exec task closes the output stream after the process terminates, so that shouldn't be the problem.
It could be a known issue with deleting on Windows. E.g.:
https://carlrice.io/blog/gradle-clean-cant-delete-file-on-windows
https://github.com/gradle/gradle/issues/9813 (but that one is about folders)
https://www.eknori.de/2020-09-18/gradle-execution-failed-for-task-appclean-unable-to-delete-file/
I would run the build with --debug to capture more details of the exception.
Are you running with the Gradle daemon? Try without it. Since it is a persistent process, maybe for some reason it has a file handle open to that file.

Main class for jar file missing for Gradle task

I have been trying to execute a jar file ssr.runner, jar using task with type JavaExec. But gradle is giving me the error that no main class specified. I am new to gradle so if any one could please elaborate in detail that would be great. Here is the task that I wrote:
task executeSqlScriptRunnerBeforeTenantCreation(type:JavaExec) {
description "Execute ssr.runner to install certificates into the device"
doLast {
if(scriptRunnerVariables.get('SSR_INTERSECT_MOCK') == 'true') {
println "Executing SQL Script Runner..."
println "Adding certificates for mocked intersect service"
if(scriptRunnerVariables.get('SSR_DB_TYPE') == 'SQL_SERVER') {
classpath = file("{$workingDir}\\ssr.runner.jar")
main = '-jar'
args '-dbtype', "${scriptRunnerVariables.get('SSR_DB_TYPE')}", '-dbhost', "${scriptRunnerVariables.get('SSR_DB_HOST')}", '-dbinstance',
"${scriptRunnerVariables.get('SSR_DB_INSTANCE')}", '-dbname', "${scriptRunnerVariables.get('SSR_DB_NAME')}", '-dbuser', "${scriptRunnerVariables.get('SSR_DB_USER')}",
'-dbpass', "${scriptRunnerVariables.get('SSR_DB_PASS')}", '-sqlscriptpath', "${scriptRunnerVariables.get('SSR_INTERSECT_MOCK_DB_SCRIPT')}"
}
}
}
}
First of all you're mixing two phases: execution and configuration. There's no need to add doLast for predefined tasks. See here. Then this is (probably) how the script should look like:
task executeSqlScriptRunnerBeforeTenantCreation(type:JavaExec) {
description "Execute ssr.runner to install certificates into the device"
if(scriptRunnerVariables.get('SSR_INTERSECT_MOCK') == 'true') {
println "Configuring SQL Script Runner..."
println "Adding certificates for mocked intersect service"
if(scriptRunnerVariables.get('SSR_DB_TYPE') == 'SQL_SERVER') {
main = '<FULLY QUALIFIED NAME OF CLASS YOU NEED TO RUN>'
classpath = file("{$workingDir}\\ssr.runner.jar")
args '-dbtype',
"${scriptRunnerVariables.get('SSR_DB_TYPE')}",
'-dbhost',
"${scriptRunnerVariables.get('SSR_DB_HOST')}",
'-dbinstance',
"${scriptRunnerVariables.get('SSR_DB_INSTANCE')}",
'-dbname',
"${scriptRunnerVariables.get('SSR_DB_NAME')}",
'-dbuser',
"${scriptRunnerVariables.get('SSR_DB_USER')}",
'-dbpass',
"${scriptRunnerVariables.get('SSR_DB_PASS')}",
'-sqlscriptpath',
"${scriptRunnerVariables.get('SSR_INTERSECT_MOCK_DB_SCRIPT')}"
}
}
}
}
main was misconfigured there should be a fully qualified (with package) name of java class you need to run passed. Of course, what is configured via classpath, main, args and so on in configuration phase will be run in execution phase only if the two expressions in if block evaluate to true.

What actually 'gradle -q task' does?

I've written a build script:
task hello // 1
hello << { // 2
println "task hello"
}
hello << { // 3
println "another task hello"
}
As I've understood //1 defines an object of Task type, //2 and //3 applies leftShift(Closure c) operator to that task. When I ran that script with command gradle -q hello I saw the following output:
task hello
another task hello
Taking that into account can we say that gradle -q task_name executes all closure's body to which operator << was applied or the command has another meaning?
gradle -q hello sets logging level to quiet (printlns are logged at that level and hence will still be shown) and executes task hello. Executing a task means executing all its task actions. Your build script adds two task actions, which will be executed in the order they were added. (<< is an alias for doLast, which adds a task action to the end of a task's list of task actions).
# gradle -h
...
-q, --quiet Log errors only.
...
No, -q switch is used to suppress all the messages that are logged to console (except error level) and print statement.
If You execute the following script:
task lol
lol << {
println '1'
}
lol << {
logger.lifecycle '2'
}
without -q switch You'll get both 1 and 2 in output. With -q switch only 1 will be printed.
<< operator is completely different thing - it's used to add action to a task. See this answer for details.

Gradle: how can I use dynamic properties on multiple tasks to fail a build?

One of my build tasks pulls information on the current SVN branch. On builds from a tag I want to be more strict and fail the build when e.g., a link checker finds dead links for the online help files. On regular builds from branches or trunk this should not break the build.
I have the following code, where the mentioned Perl script creates a properties file:
task generateSvnInfo(type: Exec) {
outputs.files "generated/svninfo"
executable "perl"
args "..."
}
Properties buildProps = new Properties()
task svninfo() {
inputs.files generateSvnInfo.outputs.files
outputs.upToDateWhen { false }
buildProps.load(new FileInputStream(inputs.files.getSingleFile()))
}
Now my other targets depend on svninfo (and the fact that it populates buildProps).
task checkHelpLinks(type: Exec) {
dependsOn "svninfo"
executable "perl"
args "..."
}
This will always fail if it finds dead help links. As far as I understand it, ignoreExitValue is false by default. To set it to true on non-tag builds, I can add this to the checkHelpLinks task:
ignoreExitValue = true
doLast {
ignoreExitValue = buildProps.FROM_TAG == "false"
}
This works, but I have four or five of these check tasks and would like to not duplicate that code around. So I tried
tasks.grep(~ /^check.+/).each { task ->
task.ignoreExitValue = true
task.doLast {
task.ignoreExitValue = buildProps.FROM_TAG == "false"
}
}
This code does not seem to get executed. I thought that may be because I compare the Task object to a String in grep, but using
tasks.grep(it.name =~ /^check.+/).each { task ->
gets me a build script error ("Could not find property 'it' on root project 'foo'.)
How can I add my tag check to all check tasks?
Is there a better way to load the properties from a file that is created as part of the build process?
Is there a SVN plugin that would do the work for me?

Categories