Gradle Copy task doesn't work with doFirst / doLast - gradle

I have a simple copy task that is successfully copying files, but not executing the doFirst/doLast items configured for the task.
Here's the code (build.gradle):
task x(type: Copy) {
copy {
from(projectDir) {
include 'build.gradle'
}
into(buildDir)
}
println "Configuring."
doFirst {
println "Inside doFirst."
}
doLast {
println "Inside doLast."
}
}
Simple enough: The single task 'x' copies the build.gradle script itself - the sole file in the project folder - into the project's build folder.
Here's execution, first ensuring there is no prior output and showing that there is an output after execution:
c:\jdev\newpaas\gradlebug>rd /s /q build & gradle x & dir build
The system cannot find the file specified.
> Configure project :
Configuring.
BUILD SUCCESSFUL in 1s
Volume in drive C is Windows
Volume Serial Number is 22A1-4AC1
Directory of c:\jdev\newpaas\gradlebug\build
01/05/2022 07:44 PM <DIR> .
01/05/2022 07:44 PM <DIR> ..
01/05/2022 07:44 PM 277 build.gradle
1 File(s) 277 bytes
2 Dir(s) 31,110,651,904 bytes free
First, the build folder was not present - hence it could not be deleted.
Gradle is showing the message in the configuration phase. But the "dofirst" and "doLast" messages are not shown.
After execution, the build folder does exist and is properly populated with a copy of the build script, suggesting that the 'x' task did in fact execute. But the messages in doFirst and doLast did not print.
There are similar questions on StackOverflow and elsewhere, but the examples I've seen have been flawed in that the code shown in those questions has shown no inputs or outputs - just doFirst and doLast - and so the answer has been that the task is already up to date and that is why it is not executing; or that the entire body of the task is preceded by '<<' and is therefore an empty task with a doLast block. This is an example of a Copy task that is configured, **is ** demonstrably executing, just not running its doFirst and doLast closures.
I am running Gradle 7.3 on Windows 10.
My need is not to print messages, but I have discovered that a project plugin's post-task configuration is not executing in Copy tasks, and it appears to boil down to this issue. I have tried using 'into('') (path to file, instead of path to folder with includes), and adding an outputs.upToDateWhen { false } entry in the task definition.

You don't have to call copy again inside your custom task. try below
task x(type: Copy) {
from(projectDir) {
include 'build.gradle'
}
into(buildDir)
println "Configuring " + projectDir
doFirst {
println "Inside doFirst."
}
doLast {
println "Inside doLast."
}
}

Related

How can I only execute specific task in build.gradle?

build.gradle is:
task copy(type: Copy, group: "Custom", description: "Copies sources to the dest directory") {
from "src"
into "dest"
println "copy"
}
task hello {
println "hello"
}
And when I try with ./gradlew copy, both copy and hello are executed. Output like below:
> Configure project :
copy
hello
How can I only execute copy?
In your example, only the copy task is executed. However, both are configured.
A Gradle build has three distinct phases in the build lifecycles:
An initialization phase
A configuration phase
An execution phase
By default, Gradle configures all tasks at start-up, though many types of configurations can be deferred (lazy configuration).
The println statement you have in the hello task is part of the configuration and this is why you see it no matter what task you intend to execute. You can also see in the output that is under the > Configure project : header.
If you want to only print "hello" when it actually executes, move it into a doLast block like this:
task hello {
doLast {
println "hello"
}
}

Gradle JAR files in a folder recursively

How can I JAR a folder and all of it's sub directories and files in a simple JAR?
I tried something like this and it does not work.
task jarVrCore(type: Jar, description: 'JARs core part of the project') {
doLast {
archiveName = "vasasdasasdasd"
from "${projectDir}"
println "${vrCoreSourceDir}"
destinationDir = file("${dirTmpLibsVr4}")
}
}
I always get an empty JAR with only the manifest.
The problem is that all of your task configurations are applied too late. You are using a doLast closure, which is executed after the actual task action (for a Jar task: the creation of the .jar file).
Normally, all task configuration is done directly inside the task configuration closure:
task jarVrCore(type: Jar, description: 'JARs core part of the project') {
archiveName = "vasasdasasdasd"
from "${projectDir}"
println "${vrCoreSourceDir}"
destinationDir = file("${dirTmpLibsVr4}")
}
If you need to apply configuration after other tasks have been executed, use a doFirst closure.
Please note, that using the example above, the println statement will be executed during configuration phase and therefore on each Gradle invocation, whether the task jarVrCore is executed or not.

Gradle force copy task to be executed

I have the following task to copy a file:
task copyFiles(type: Copy) {
def folder = rootProject.file('/a/b/c')
println folder.absolutePath
println folder.exists()
from(folder) {
include '*.*'
}
into(rootProject.file('/c/b'))
}
I am trying to execute this task as a standalone copy task, so without any binding to the compiling of the project etc.
The problem is that the task is never executed (NO-SOURCE) despite the folder existing:
C:\...\a\b\b
true
:projectName:copyFiles NO-SOURCE
NO-SOURCE means that the copy task did not find any files to copy based on your configuration.
If /a/b/c are directories as sub-directories in relation to your build.gradle project file then this should work provided that the /c folder contains any files that follow the *.* pattern for names.
https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Copy.html

Gradle copy task not finding source files when leftShift (<<) operator used

I have the following gradle task in a subproject's build.gradle file to copy file.txt from a directory called from_dir/ to a directory to_dir/ and rename it to fileRenamed.txt:
task copyRenameFile(type: Copy) {
System.out.println("copyRenameFile begin")
from('from_dir')
into('to_dir')
include('file.txt')
rename('file.txt', 'fileRenamed.txt')
System.out.println("copyRenameFile end")
}
build.finalizedBy(copyRenameFile)
When I run gradlew :subprojectname:build, this task performs the copy as expected after the build task is finalized, but it executes the printlns during the configuration phase, before the build task.
In an attempt to make the printlns appear after the build phase when the copy is actually being executed, I tried using the << operator like so:
task copyRenameFile(type: Copy) << {
But this results in the task beings skipped with the following message:
[INFO] [org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter] Skipping task ':subprojectname:copyRenameFile' as it has no source files.
Does this mean file.txt could not be found during the execution phase? Why?
EDIT: After reading this answer, I now understand that my usage of the << operator is causing the configuration phase to skip this task and this is the reason the source files are not found. So I guess I can't use the << operator, but how else can I make the printlns occur when the task is being executed and not when it is being configured?
I figured it out:
task copyRenameFile(type: Copy) {
doFirst{
System.out.println("copyRenameFile begin")
}
from('from_dir')
into('to_dir')
include('file.txt')
rename('file.txt', 'fileRenamed.txt')
doLast{
System.out.println("copyRenameFile end")
}
}
build.finalizedBy(copyRenameFile)
I got rid of the << and instead used doFirst and doLast to ensure my printlns occured during the execution phase.

Dynamically created task of type Copy is always UP-TO-DATE

I've prepared a very simple script, that illustrates the problem I see using Gradle 1.7 (need to stick with it because of some plugins not yet supporting newer versions).
I'm trying to dynamically create tasks each of which corresponds to a file in the project directory. This works fine, but the tasks I create never get executed as soon as I assign them type 'Copy'.
Here is my problem build.gradle:
file('templates').listFiles().each { File f ->
// THIS LINE DOES NOT WORK
task "myDist-${f.name}" (type: Copy) {
// NEXT LINE WORKS
//task "myDist-${f.name}" {
doLast {
println "MYDIST-" + f.name
}
}
}
task distAll(dependsOn: tasks.matching { Task task -> task.name.startsWith("myDist")}) {
println "MYDISTALL"
}
defaultTasks 'distAll'
in this way my tasks do not get executed when I call default task calling simply gradle:
MYDISTALL
:myDist-template1 UP-TO-DATE
:myDist-template2 UP-TO-DATE
:distAll UP-TO-DATE
BUILD SUCCESSFUL
If I remove type Copy from my dynamic task (uncommenting the line above), my tasks get executed:
MYDISTALL
:myDist-template1
MYDIST-template1
:myDist-template2
MYDIST-template2
:distAll
BUILD SUCCESSFUL
(You'll need to create a folder name templates in the same directory where build.gradle is located and put couple of empty files into there in order to run the test)
According to the debug output:
Skipping task ':myDist-template1' as it has no source files.
Skipping task ':myDist-template2' as it has no source files.
So how can I specify source files and make my Copy tasks execute?
I've tried adding
from( '/absolute/path/to/existing/file' ) {
into 'myfolder'
}
to the task body, I've tried assigning task's inputs.source file('/my/existing/file') with no success.
Could you please advise on how to modify my simple script leaving dynamic task creation and keeping my dynamic tasks of type Copy?
Thank you!
Edit:
All right, this way the task gets called:
file('templates').listFiles().each { File f ->
task "myDist-${f.name}" (type: Copy) {
from f
into 'dist'
doLast {
println "MYDIST-" + f.name
}
}
}
but it looks I must always specify from/into. It doesn't suffice to do that in the doLast{} body.
A Copy task only gets executed if it has something to copy. Telling it what to copy is part of configuring the task, and therefore needs to be done in the configuration phase, rather than the execution phase. These are very important concepts to understand, and you can read up on them in the Gradle User Guide or on the Gradle Forums.
doFirst and doLast blocks get executed in the execution phase, as part of executing the task. Both are too late to tell the task what to copy: doFirst gets executed immediately before the main task action (which in this case is the copying), but (shortly) after the skipped and up-to-date checks (which are based on the task's configuration). doLast gets executed after the main task action, and is therefore clearly too late.
I think the following Gradle User Guide quote answers my question the best:
Secondly, the copy() method can not honor task dependencies when a task is used as a copy source (i.e. as an argument to from()) because it's a method and not a task. As such, if you are using the copy() method as part of a task action, you must explicitly declare all inputs and outputs in order to get the correct behavior.
Having read most of the answers to "UP-TO-DATE" Copy tasks in gradle, it appears that the missing part is 'include' keyword:
task copy3rdPartyLibs(type: Copy) {
from 'src/main/jni/libs/'
into 'src/main/libs/armeabi/'
include '**/*.so'
}
Putting from and into as part of the doLast section does not work. An example of a working task definitions is:
task copyMyFile(type: Copy) {
def dockerFile = 'src/main/docker/Dockerfile'
def copyTo = 'build/docker'
from dockerFile
into copyTo
doLast {
println "Copied Docker file [$dockerFile] to [$copyTo]"
}
}
Not the behavior I was expecting.
Using gradle 3.2.1

Resources