Gradle Zip Task: Add Dynamically Generated File - gradle

I have a gradle build script in which I'm using the 'Zip' task to generate a zip archive directly from a source directory.
In addition to copying over all the files inside the source directory structure into the zip archive, I'm looking for a way to include a dynamically generated file that's not in the source directory.
Do you guys know how I can do this?
Here's pseudo code of what I want to do:
task('archive', type: Zip) {
...
from 'source'
newFile('dynamically-generated.txt', 'dynamic file content')
}
And here are the source and destination structures:
[i71178#bddev01-shell01 ~]$ tree source/
source/
├── file1.txt
├── file2.txt
└── file3.txt
0 directories, 3 files
[i71178#bddev01-shell01 ~]$ unzip -l destination.zip
Archive: destination.zip
Length Date Time Name
--------- ---------- ----- ----
0 02-26-2016 16:56 source/
0 02-26-2016 16:56 source/file2.txt
0 02-26-2016 16:56 source/dynamically-generated.txt
0 02-26-2016 16:56 source/file1.txt
0 02-26-2016 16:56 source/file3.txt
--------- -------
0 5 files

Combining my comments above and your getTemporaryDir comment:
task generateThenZip()<<{
def tempDir = getTemporaryDir()
newFile("$tempDir/dynamically-generated.txt", 'dynamic file content')
zip{
from 'source'
from tempDir
}
}

This is what I ended up doing:
subprojects {
apply plugin: 'myPlugin'
//The 'build' task is set up by the plugin
build {
//Customization to keep consistent with artifacts being currently generated.
doFirst {
new File(getTemporaryDir(), 'artifact-fullname.txt').text = "${project.name}-${project.version}\n"
}
archiveName = "${project.name}.${project.build.extension}"
from getTemporaryDir()
}
}
Thanks!

I have managed to achieve it quite easyly on Gradle 6.6.1
by just creating the file in the from section.
distributions {
main {
contents {
into("/") {
from {
if (!buildDir.exists()) {
buildDir.mkdir()
}
def f = new File("$buildDir/all")
f.text = "project_version: ${project.version}\n"
f
}
}
...
}
}
}
btw. I think $buildDir is safer than /tmp

Related

How to delete all "target" directories from gradle (after converting from maven)

I have a huge maven project, lot of people are using it. I'm currently working on converting it to gradle. One of the last steps will be that I merge the gradle files, and delete the pom.xml files. But I'd like to add a gradle task to clean the maven target directories (of all the sub-projects). In shell I would do something like:
find . -type d -name target -exec rm -rf "{}" \;
But I prefer this to be a gradle task. How do I add it? This is what I tried but it doesn't delete anything:
task cleanMaven(type: Delete) {
delete fileTree('.').matching { include '**/target/**' }
}
below will handle all modules of root project and prints true if a target dir existed and is deleted
allprojects {
task mvnClean {
doFirst {
def targetPath = project.projectDir.toString() + '/target'
println "target dir exists: ${Files.deleteIfExists(Paths.get(targetPath))}"
}
}
}
Based on #PrasadU's answer, but this also deletes all the contents of the target/ directories:
allprojects {
task mvnClean {
doFirst {
def targetPath = project.projectDir.toString() + '/target'
project.delete(files("${targetPath}"))
}
}
}

What Is The Current Path In A Gradle Multi-Module Project?

I have a multi-module project that ends up outputting a directory called logs at the root of each module - including the root project.
I have extended the clean task like this but it only deletes the logs dir in the root project and not in the sub-modules.
allprojects {
clean {
delete 'logs'
}
}
I thought that this meant "add the clean task to all the projects and delete the logs dir in each project".
It seems like even though the delete is being called in each sub-module, it is using the root directory as the relative path to find the logs dir.
However, if I change it to the following it deletes the directory in each module.
allprojects {
clean {
delete file('./logs')
}
}
This looks functionally identical to me since if the path of each clean task is relative to the root then file('./logs') should also be relative to the root.
However, the file object seems to be relative to the module dir and not the root.
Why does the file object resolve correctly but the string passed to the clean task does not?
How are paths resolved for each module when running a multi-module project?
Is there a better way to do this than using a file object?
Could not replicate - gradle 6.7 / jdk 11
Dir structure
.
|____a
| |____b
| |____c
common delete task
allprojects {
apply plugin: 'java'
task deleteLogs(type: Delete) {
delete 'logs'
}
clean {
delete 'logs'
}
task printcd {
println 'project : ' + project.name
println 'rootDir : ' + project.rootDir
println 'prjDir : ' + project.projectDir
println '-------------'
println 'file : ' + file('logs').absolutePath
println 'file ./ : ' + file('./logs').absolutePath
println '-------------'
print 'deletePath : '
project.tasks.getByName('deleteLogs').targetFiles.each {file -> println file.absolutePath }
println '-------------'
print 'clean : '
project.tasks.getByName('clean').targetFiles.each {file -> print file.absolutePath + " , " }
println ''
println '============='
}
repositories {
mavenCentral()
}
}
output
-bash$ gradle printcd
> Configure project :
project : a
rootDir : /Users/xyz/a
prjDir : /Users/xyz/a
-------------
file : /Users/xyz/a/logs
file ./ : /Users/xyz/a/logs
-------------
deletePath : /Users/xyz/a/logs
-------------
clean : /Users/xyz/a/build , /Users/xyz/a/logs ,
=============
project : b
rootDir : /Users/xyz/a
prjDir : /Users/xyz/a/b
-------------
file : /Users/xyz/a/b/logs
file ./ : /Users/xyz/a/b/logs
-------------
deletePath : /Users/xyz/a/b/logs
-------------
clean : /Users/xyz/a/b/build , /Users/xyz/a/b/logs ,
=============
project : c
rootDir : /Users/xyz/a
prjDir : /Users/xyz/a/c
-------------
file : /Users/xyz/a/c/logs
file ./ : /Users/xyz/a/c/logs
-------------
deletePath : /Users/xyz/a/c/logs
-------------
clean : /Users/xyz/a/c/build , /Users/xyz/a/c/logs ,
=============
BUILD SUCCESSFUL in 578ms
-bash$ gradle --version
------------------------------------------------------------
Gradle 6.7
------------------------------------------------------------
JVM: 11.0.8 (Oracle Corporation 11.0.8+10-LTS)

How do I exclude all subdirectories from Gradle zip task using Ant include/exclude pattern?

I want to create a task that will zip up all the files in a directory, ignoring all subdirectories. At the same time, I want to iterate through all the subdirectories and create zips that include the files in those directories (and ignoring any further subdirectories).
Thus, for this directory structure, I want the following zips:
$ls build/dirA
fileA
dirB
$ls build/dirA/dirB
fileB
I should get zip/zipA containing fileA, zip/zipB containing fileB.
I am using code based on the answer here: gradle task to zip multiple directories independently Essentially, I create a zip task for each zip artifact to be created, with a dependency on the top level task.
task myZip() {
file('build').eachDir { dir ->
dir.eachDir { sub ->
dependsOn tasks.create("zip$sub.name", Zip) {
from sub
baseName sub.name
destinationDir file('zip')
}
}
dependsOn tasks.create("zip$dir.name", Zip) {
from dir
baseName dir.name
excludes ['*/**']
destinationDir file('zip')
}
}
}
The problem seems to be in the exclude pattern. I get the correct zips for the sub directories, but the parent directory includes fileA and dirB/fileB.
What is the correct way to do this please?
*Note I have not put an exclude for the iteration through the subdirectories, as I figure this pattern needs to be the same as for the parent directory, which I haven't figured out yet.
You can try below script, it would resolve your issue:
import static groovy.io.FileType.DIRECTORIES
task myZip {
file('folder').traverse(type: DIRECTORIES) {
def path = it.path
def zipFile = it.name + '.zip'
ant.zip(destfile: zipFile){
fileset(dir: path) {
include (name: "*")
type (type: "file")
}
}
}
doLast {
copy {
from "."
include "*.zip"
into file("zip")
}
}
}
Here is some example test:
$ tree folder
folder
└── dirA
├── dirB
│   ├── dirC
│   │   ├── dirD
│   │   └── fileC
│   └── fileB
└── fileA
4 directories, 3 files
And it generate the three zip files into zip folder as well as root folder.
$ ls -1 zip/
dirA.zip
dirB.zip
dirC.zip

Some files are not included during a Tar Gradle task

I just observed a very weird behaviour from a Gradle Tar task.
Let's take a simple example, 2 files :
/tmp/test$ ls
test1.txt ##test2##
Here is a simple Tar task :
task('testHash', type: Tar) {
from "/tmp/test"
extension = 'tar.gz'
compression = Compression.GZIP
}
The file ##test2## is skipped for some reason, after running gradle testHash :
/path/to/gradle/project/foo$ tar tvf build/distributions/foo-1.0.tar.gz
test1.txt
It seems to happen when the filename is containing # character both at the beginning and the end.
A regular tar is working well :
/tmp/test$ tar czvf test.tar.gz *
test1.txt
##test2##
/tmp/test$ tar tf test.tar.gz
test1.txt
##test2##
I am using Gradle 4.1. Any explanation ?
Thanks to Opal's comments, I adjusted my searches and found a workaround. There is maybe a cleaner way but this one works for me
task('testHash', type: Tar) {
doFirst {
org.apache.tools.ant.DirectoryScanner.defaultExcludes.each {
DirectoryScanner.removeDefaultExclude it
}
}
from "/tmp/test"
extension = 'tar.gz'
compression = Compression.GZIP
}
FYI, here are default excludes
There are a set of definitions that are excluded by default from all
directory-based tasks. As of Ant 1.8.1 they are:
**/*~
**/#*#
**/.#*
**/%*%
**/._*
**/CVS
**/CVS/**
**/.cvsignore
**/SCCS
**/SCCS/**
**/vssver.scc
**/.svn
**/.svn/**
**/.DS_Store
Ant 1.8.2 adds the following default excludes:
**/.git
**/.git/**
**/.gitattributes
**/.gitignore
**/.gitmodules
**/.hg
**/.hg/**
**/.hgignore
**/.hgsub
**/.hgsubstate
**/.hgtags
**/.bzr
**/.bzr/**
**/.bzrignore

Copy entire directory in Gradle

I have a directory structure like this:
file1.txt
file2.txt
dir1/
file3.txt
file4.txt
I want to use Gradle to copy that entire structure into another directory. I tried this:
task mytest << {
copy {
from "file1.txt"
from "file2.txt"
from "dir1"
into "mytest"
}
}
But this results in the following:
mytest/
file1.txt
file2.txt
file3.txt
file4.txt
See, the copy from dir1 copied the files in dir1, whereas I want to copy dir1 itself.
Is it possible to do this directly with Gradle copy?
So far, I have only been able to come up with this solution:
task mytest << {
copy {
from "file1.txt"
from "file2.txt"
into "mytest"
}
copy {
from "dir1"
into "mytest/dir1"
}
}
For my simple example there's not much to it, but in my actual case there are many directories I want to copy, and I'd like to not have to repeat so much.
You can use . as the directory path and include to specify, which files and directories you want to copy:
copy {
from '.'
into 'mytest'
include 'file*.txt'
include 'dir1/**'
}
If both from and into are directories, you'll end up with the full copy of the source directory in the destination directory.
I know this is a bit late, but I tried #Andrew solution above and it copied everything inside the directory.
"." is not required nowadays to represent a direct in gradle.
So I did some research
and found this
and created the following code (with Up-to-date check) based on it:
task resourcesCopy() {
doLast {
copy {
from "src/main/resources"
into "./target/dist/WEB-INF/classes"
}
copy {
from "GeoIP2.conf"
into "./target/dist/WEB-INF"
}
}
}
I don't know how long this syntax has been around, but it seems a little clearer.
task copyToRelease(dependsOn: [deletePreviousRelease], type: Copy) {
from('build/dist') {
include '**/*.*'
}
destinationDir(new File('../htmlrelease/src/main/webapp/canvas'))
}
Maybe also helpful: Usage of fileTree to copy an entire directory recursively, e.g.,
task mytest << {
copy {
from fileTree('.')
into "mytest"
}
}

Resources