I am using gradle 4.9.
DoFirst () and doLast () are not executed using Copy type.
task myCopyExtension(type : Copy){
from 'original'
into 'target'
File newFile = file('original/newFile.txt')
doFirst {
println 'write to file'
newFile.write('copy file', 'UTF-8')
}
doLast {
File copied = file('original/newFile_copied.txt')
if(newFile.renameTo(copied)){
println 'copy complete'
}else {
println 'copy failed'
}
}
}
gralde myCopyExtension
noting pring
append -----
task myCopy(type : Copy) {
doLast{
println 'myCopy!!'
}
}
gradle myCopy
Nothing is output.
T_T
Before your task executes gradle will do an up to date check to see if the task inputs/outputs have changed since last time it ran. So if 'original' and 'target' folders haven't changed since last execution gradle will skip the task
Also, you shouldn't mutate files which are used as task inputs as it will ruin up to date checking.
See https://docs.gradle.org/current/userguide/more_about_tasks.html#sec:up_to_date_checks
Related
I'm wondering how I can pass a parameter (PARAM) to a Gradle task from another Gradle task that depends on it.
For example something along these lines
task buildDist(PARAM) {
copy {
from "$projectDir/src/{PARAM}/ClientBanner.json"
into "$buildDir/${project.name}/"
}
and call this Gradle task from another one like:
task dist(type: Zip) {
from "$buildDir"
include "${project.name}/**/*"
archiveFileName = project.name + '.zip'
destinationDirectory = layout.buildDir.dir('dist')
dependsOn('buildDist(PARAM)')
}
#Shapebuster
The Gradle build script is Groovy (or Kotlin) based and can be extended using the supported syntax of that language. So, in your example, you should be able to use the PARAM like so:
task buildDist(String param1) {
copy {
from "$projectDir/src/$param1/ClientBanner.json"
into "$buildDir/${project.name}/"
}
}
and then:
task dist(type: Zip) {
from "$buildDir"
include "${project.name}/**/*"
archiveFileName = project.name + '.zip'
destinationDirectory = layout.buildDir.dir('dist')
dependsOn buildDist("$param1")
}
I'm trying trying to run a gradle task only when an environment Variable is set. I found this onlyIf function in https://discuss.gradle.org/t/how-do-i-run-a-task-only-if-an-environment-variable-is-defined/12438
So I wrote this
task onlyRunIfItIsCI() {
println System.env['CI']
onlyIf {
System.env['CI'] == "true"
}
}
However, regardless of if I set the CI or not, it still got run. Did I miss anything?
Apparently in Gradle, it has 2 pass of execution, first is configuration, and second is execution.
The configuration will be run regardless of the onlyIf. To ensure the onlyIf is in effect, we should wrap the common execution under the gradle specific scope e.g. doFirst or doLast
task onlyRunIfItIsCI() {
doFirst {
println System.env['CI']
}
doLast {
println System.env['CI']
}
onlyIf {
System.env['CI'] == "true"
}
}
clean.dependsOn onlyRunIfItIsCI
Do note, we need to have it dependsOn, for the actual execution.
Another example is where the from and into is gradle specific command where will not run during configuration.
task copyPreCommitToGitHook(type: Copy) {
from new File(rootProject.rootDir, 'storage/pre-commit')
into { new File(rootProject.rootDir, '.git/hooks') }
onlyIf {
System.env['CI'] == null
}
}
tasks.getByPath(':app:preBuild').dependsOn copyPreCommitToGitHook
When I try to create a zip file in the execution phase of a Zip typed gradle task no zip file is created.
If I perform the same in the configuration phase (leaving out the doLast statement), the zip file is created without problems.
The doLast block is called since the println statement is shown in the output logging.
The reason that we need to generate the zip in the execution phase is because the file which needs to be compressed is the result of the compile execution.
I have also tried to solve this with a jar task, but this gives me similar problems.
Here's the code:
task createClassPathJar(type: Zip) {
dependsOn("createManifest")
from("${projectRoot}") {
include "MANIFEST.MF"
}
archiveName = "dummy.jar"
doLast {
destinationDir(file("${projectRoot}"))
archiveName = "zipfile.jar"
println "executing phase createClassPathJar. archiveName: " + archiveName
}
}
Can someone help me here ? I'm using Gradle v6.4.1.
You cannot use doLast to configure the action of your task, because it will be executed after the particular action (in this case the zipping) has run. Either use a doFirst closure or setup your task configuration in a way that it does not depend on other configurations:
As an example, depending on how properly your task createManifest defines its output, you may use it directly to define the Zip task content using "from createManifest".
I guess your reason for using a doLast closure is the call to destinationDir that is based on a variable. Instead, you may just use a closure that evaluates the variable lazily:
task createManifest {
outputs.file('path/to/MANIFEST.MF')
}
task createClassPathJar(type: Zip) {
from createManifest
archiveName = 'zipfile.jar'
destinationDir = file({ "${projectRoot}" }) // or just file({ projectRoot })
}
Try with doFirst instead of doLast:
task createClassPathJar(type: Zip) {
dependsOn("createManifest")
from("${projectRoot}") {
include "MANIFEST.MF"
}
archiveName = "dummy.jar"
doFirst {
destinationDir(file("${projectRoot}"))
archiveName = "zipfile.jar"
println "executing phase createClassPathJar. archiveName: " + archiveName
}
}
I don't know about your case but I tried myself by changing the archive name to the current time in the doFirst block, and the archive name was effectively matching the time of execution and not of configuration.
I am trying to make my task zipGui execute on build target, but the only way I seem to be able to execute a task is if I remove the (type: Zip) from the task definition.
This snippet fails to execute the zipGui task at all:
task zipGui(type: Zip) {
doFirst {
println "==================== Zipping GUI components"
}
doLast {
FileTree zip = zipTree('assets/htdocs/gui.zip')
from 'assets/htdocs'
}
}
build.dependsOn zipGui
And this executes the zipGui but it doesn't know anything about how to zip files:
task zipGui {
doFirst {
println "==================== Zipping GUI components"
}
doLast {
FileTree zip = zipTree('assets/htdocs/gui.zip')
from 'assets/htdocs'
}
}
build.dependsOn zipGui
This is a stripped down fragment of the overall build.gradle.
How can I get zipGui to execute as a dependency of the build?
EDIT: here is more of the real build.gradle without me stripping things out to simplify the question:
task copyCert(type: Copy) {
from '../../../install'
into 'assets/certs/root'
include 'ca.pem'
doFirst {
println "==================== Copying root cert into assets"
}
}
task copyGui(dependsOn: copyCert, type: Copy) {
from '../../web/gui'
into 'assets/htdocs'
include '**/*.html'
include '**/*.css'
include '**/*.js'
include '**/*.wav'
include '**/*.tmpl'
include '**/*.png'
include '**/*.gif'
include '**/*.jpg'
exclude '**/*.DS_Store'
exclude '**/.gitignore'
exclude '**/.thumb'
exclude '**/build'
doFirst {
println "==================== Copying gui components into assets"
}
}
task zipGui(dependsOn: copyGui, type: Zip) {
FileTree zip = zipTree('assets/htdocs/gui.zip')
from 'assets/htdocs'
doFirst {
println "==================== Zipping GUI components"
}
}
Check details of zip task here: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Zip.html
task zipGui(type: Zip) {
archiveName = 'gui.zip'
from("$projectDir/../../../install") {
into 'assets/certs/root'
include 'ca.pem'
}
from("$projectDir/../../web/gui"){
into 'assets/htdocs'
exclude '**/*.DS_Store'
exclude '**/.gitignore'
exclude '**/.thumb'
exclude '**/build'
} // Just include or exclude is enough here as you indicated.
destinationDir(file("$buildDir/libs"))
}
Your task simply has nothing to do.
Gradle tasks are only executed, if they have something to do. If there is nothing to do (e.g. no files to zip), a task is skipped. There are multiple reasons for a task to have nothing to do. The main reason are up-to-date checks to prevent Gradle from doing the same thing what was done during the last invocation, at least as long as the task outputs are still available and the task inputs did not change.
However, in your specific case, the task has nothing to do, because at the time the task executes, no input files are specified at all. Files to include into the zip file can be added via from, which you do use. But, you use it inside a doLast closure, which is executed after the task actions (where the zipping takes place) were executed. Therefor, when running the zip process, the configuration did not take place.
You could use the regular configuration closure of the task or even the doFirst closure to configure your task:
task zipGui(type: Zip) {
from 'assets/htdocs'
}
// OR
task zipGui(type: Zip) {
doFirst {
from 'assets/htdocs'
}
}
Some more remarks:
The line FileTree zip = zipTree('assets/htdocs/gui.zip') does absolutely nothing, because the created file tree is not queried. You need to either access the files of the file tree manually or pass it to a task, e.g. your zip task: from zipTree('assets/htdocs/gui.zip')
In the second example, the task is executed because for normal tasks there are no automatic checks if there is any work to do, since a normal task can basically do everything the user makes it do.
I'm not quite sure, but I think the second example should throw an exception, because a normal task without a type does not provide a from method.
To get the status of each executed task and more insight generally, use the command line parameter --console=plain. The parameters -d and --stacktrace / --full-stacktrace may be used to get more information on errors.
I am trying to explode some jar files in a doFirst block as follows -
task copyBinaries(type: Copy){
def Jar1 = ""
def Jar2 = ""
def Jar3 = ""
doFirst {
Jar1 = configurations.Lib1.singleFile
Jar2 = configurations.Lib2.singleFile
Jar3 = configurations.Lib3.singleFile
}
inputs.files configurations.Lib1
inputs.files configurations.Lib2
inputs.files configurations.Lib3
from(zipTree(file(Jar1))) {
into('jar_folder1')
}
from(zipTree(file(Jar2))) {
into('jar_folder2')
}
from(zipTree(file(Jar3))) {
into('jar_folder3')
}
into('build/libs/')
}
}
In order the avoid resolution of dependencies in the configuration phase, I am extracting the file names from the configurations in the doFirst block. The problem is, since the Copy task needs the source and destination of copy during configuration phase, gradle sees Jar1, Jar2, Jar3 as empty strings and throws and error.
I am looking for a way to let the Copy task receive arguments (source file) during execution phase (after doFirst block is executed).
How can I address this situation? Thanks.
I've had a similar situation where I had to copy from a path that was created as output of another one.
I solved this with just declaring the copy logic in my task's doLast block:
task copyStuff {
doLast {
copy {
from zipTree('path/to/archive')
into 'destination/dir'
}
}
}
You just have to make sure, that your task runs after the task that creates the needed outputs with using dependsOn for example.