Gradle force copy task to be executed - gradle

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

Related

Gradle Copy task doesn't work with doFirst / doLast

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."
}
}

How to create a war file from a directory in gradle

I am writing a task to unzip a war file, remove some jars and then create a war from extracted folder.
task unzipWar(type: Copy){
println 'unzipping the war'
def warFile = file("${buildDir}/temp/libs/webapps/service-app.war")
def warOutputDir = file("$buildDir/wartemp")
from zipTree(warFile)
into warOutputDir
}
task deleteJars(type: Delete){
println 'deleting the logging jars'
file("$buildDir/wartemp/WEB-INF/lib/slf4j-api-1.7.5.jar").delete();
file("$buildDir/wartemp/WEB-INF/lib/logback-classic-1.1.7.jar").delete();
file("$buildDir/wartemp/WEB-INF/lib/logback-core-1.1.7.jar").delete();
}
task createWar(type: War){
destinationDir = file("$buildDir")
baseName = "service-app"
from "$buildDir/wartemp"
dependsOn deleteJars
}
For some reason, the jars are not getting deleted and the war file is getting created which only includes MANIFEST.MF and nothing else. What am I missing here?
First thing to note, is that your createWar task depends on deleteJarstask, but deleteJars doesn't depend on unzipWar. It seems, that if you call the createWar task it won't call unzipWar task and there will be nothing to copy or delete. Note that you have a MANIFEST.MF file, because it was generated by createWar task.
And the second thing is that you are trying to delete some files in the configuration stage of the build, though your unzipWar will do it's job in the execution phase. So your delete task will try to delete this files just before they are even unzipped. You can read about build lifecycle in the official userguide. So you need to rewrite your deleteJars task, to configure it properly. Take a look into the docs, it has an example how to do it.
So if you call a
file("$buildDir/wartemp/WEB-INF/lib/slf4j-api-1.7.5.jar").delete();
it tries to delete your files at the time it's called, because it's not a task property, but an action at the configuration.
To configure it you have to do something like:
task deleteJars(type: Delete) {
delete "$buildDir/wartemp/WEB-INF/lib/slf4j-api-1.7.5.jar", "$buildDir/wartemp/WEB-INF/lib/logback-classic-1.1.7.jar", "$buildDir/wartemp/WEB-INF/lib/logback-core-1.1.7.jar"
}

Zip task marked as up-to-date

Hi I try to collect plugins from sub-folder, zip them and copy to my export folder.
task buildPlugin {
dependsOn ':empty-plugin:build'
}
task exportPlugin(type: Zip) {
dependsOn buildPlugin
// create new export folder as destination for nightly build
def folder = '/export';
def file = "${project.name}-sdk-${project.version}";
// collect all plugins into cwc-sdk zip file
baseName = file
fileTree("cwc-plugin").each({
if (it.name.endsWith(".zip")) {
from it.absolutePath
}
})
// move cwc-sdk zip file into export destination folder
copy { into folder from file }
delete file
}
I run clean task first. The gradle logs:
:api:compileJava
:api:processResources
:api:classes
:api:jar
:empty-plugin:compileJava
:empty-plugin:processResources
:empty-plugin:classes
:empty-plugin:jar
:empty-plugin:assemble
:empty-plugin:compileTestJava UP-TO-DATE
:empty-plugin:processTestResources UP-TO-DATE
:empty-plugin:testClasses UP-TO-DATE
:empty-plugin:test UP-TO-DATE
:empty-plugin:check UP-TO-DATE
:api:javadoc
:empty-plugin:zip
:empty-plugin:build
:buildPlugin
:exportPlugin UP-TO-DATE
BUILD SUCCESSFUL
Total time: 2.097 secs
While first run :exportPlugin is marked as UP-TO-DATE and I don't get the zipped file from build. When I run :exportPlugin again everything is fine. It's also fine when I chain both tasks manually (rungradle clean, next run gradle buildPlugin, run gradle exportPlugin by doublclick to tasks at IDEA)
I think the order of tasks are still ok. I don't need to work with mustRunAfter.
I also played around with copySpec, buildplugin.outputs.files. But nothing helps.
Can anybody help me to solve this issue for initial build run?
Thanks!
Update:
A Zip task is an abstracted Copy task
AbstractCopyTask is the base class for all copy tasks. (Docu)
I found this comment from Peter Niederwieser
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.
How do I change from it.absolutePath code line inside fileTree loop to be part during configuration phase?

Fail Gradle Copy task if source directory not exist

I'm using Gradle to create a build script. I want to protect the script from wrong properties, one of the tasks in the script is simple Copy task and I notice that when I put non-exist directory as from parameter the task continue with Skipping task ':copySpecificPlatform' as it has no source files.
Is there a way to cause the copy task to fail in this case?
This worked for me:
task copySpecificPlatform(type: Copy) {
from 'source/directory'
into 'target/directory'
if(inputs.sourceFiles.empty) throw new StopExecutionException("No files found")
}
You can try:
task cp(type: Copy) {
from 'empty'
into 'target'
inputs.sourceFiles.stopExecutionIfEmpty()
}
Every Task has its TaskInputs which source files are a FileCollection that has special method which configures the desired behavior.

Conventional way of copying files in Gradle - use Copy task or copy method?

I'm adding a task to deploy war files to Tomcat .. the only thing that the task needs to do is copy the war file to the TOMCAT location.
There 2 ways that I can think of implementing this .. but being new to gradle, I'm not quite sure what's more conventional/right (or if it even matters).
task myCopy(type: Copy)
myCopy.configure {
from('source')
into('target')
include('*.war')
}
or
task myCopy{
doLast{
copy {
from 'source'
into 'target'
include '*.war'
}
}
}
In most cases (including this one), the Copy task is the better choice. Among other things, it will give you automatic up-to-date checking. The copy method is meant for situations where (for some reason) you have to bolt on to an existing task and cannot use a separate task for copying.
The code for your Copy task can be simplified to:
task myCopy(type: Copy) {
from('source')
into('target')
include('*.war')
}
UP-TO-DATE only verifies the file is in place but not if the files has changed
to avoid being cached with an old file use
outputs.upToDateWhen { false }

Resources