Extracting single jar inside zip using gradle task - gradle

I’m trying to extract a jar from a zip file which is available inside the zip as below structure.
test.zip /web-inf /lib /result1.jar
Here is the task:-
task unzip(type: Copy){
group "testgroup"
def zipFile = file("$buildDir/test.zip")
def tree = zipTree(zipFile)
from(tree.matching { include "**/result1.jar"})
into "$builddir/dir"
includeEmptyDirs = false
}
But I am getting jar file with folder structure like /web-inf/lib/result1.jar. I want jar file alone, not the folders (/web-inf/lib/).
Please correct what is wrong in the gradle task.

Gradle Copy DSL provides a method eachFile (Closure closure) that you can use to perform action on each file which will be copied/extracted, see Copy DSL
In your case, you can use this method to rename (remove parent dirs from path) your file:
task unzip(type: Copy) {
group "testgroup"
from( zipTree(file("test.zip")).matching { include "**/result1.jar" } )
into "$buildDir/dir"
def parentDir = "web-inf/lib"
eachFile { fcp ->
fcp.path = fcp.path.replaceFirst("^$parentDir", '')
}
includeEmptyDirs = false
}

Related

gradle - create jar iteratively under a certain directory

I am trying to create multiple jars. I have a certain directory which contains multiple directory. Each directory has its own files(xml and sql). So I am trying to create a jar with a subdirectory name and all the files in it. Those jars will be used for junit test, so I want to create it during configuration phase in advance.
The target directory "../dist" exists outside this project.
ext.createTemplateJar = { sourceDirectory, jarFileName ->
jar {
archiveName = jarFileName
from sourceDirectory
includeEmptyDirs = false
manifest
{
attributes 'Implementation-Title' : VENDOR_NAME
}
}
println "creating a jar for ${jarFileName}"
}
tasks.withType(Jar) {
destinationDir = file("../dist")
}
task generateTemplates {
new File("${projectDir}/templates").eachFile() { file ->
if (file.isFile()) {
return
}
println "template dir is ${file.path}"
createTemplateJar(file.path, "${file.name}.jar")
}
}
When I execute this gradle generateTemplates, it runs fine, but I don't see any jar files created in the destination directory.
It seems something wrong, but I can't tell.
You should create multiple Jar tasks, one for each subdirectory inside ${projectDir}/templates, and have your generateTemplates task do nothing but depend on all of those tasks. For example (I renamed generateTemplates to allJars):
task allJars {
}
file("${projectDir}/templates").eachFile { f ->
def taskName = "jar${f.name.capitalize()}"
tasks.create(name: taskName, type: Jar) {
archiveName = "${f.name}.jar"
destinationDir = file('../dist')
// Configure each JAR however you want
}
allJars.dependsOn taskName
}
Example build:
$ ls templates/
bar baz foo test
$ ./gradlew clean allJars
:clean
:jarBar
:jarBaz
:jarFoo
:jarTest
:allJars
BUILD SUCCESSFUL
Total time: 0.615 secs
$ ls ../dist/
bar.jar baz.jar foo.jar test.jar

Gradle: remove some files from an existing war | for each war-file do: unpack, remove/filter, assemble war

I'm relatively new to gradle, so this might be a typical newbee-question.
In our gradle build, we have a set of war files (dependencies) that all include a file that we need to remove from those war files, before building our ear file.
How can I achieve the following:
- for all war files in a folder,
- extract war content to a location (using a Copy task & zipTree)
- re-pack to a new war applying a filter (using War & excludes)
I assume I'll create a new task and add some 'dependsOn' declarations.
task excludeUnwantedFiles(){
file(directoryWithOriginalWars).eachFile { file ->
???? unpack war, filter, assemble new war file ????
}
}
ear.dependsOn(excludeUnwantedFiles)
excludeUnwantedFiles.dependsOn(downloadAllOriginalWarsIntoDirectory)
How do I create that task, that executes for each war-file? What is the best way to do this?
Is there a way I can to this in one task? E.g. with the Copy task and using zipTree(fooBarWithFile.war) as 'from' and 'war(fooBarWithoutFile.war)' and applying a filter in between?
Or is this the way to go, just with a loop? Delete/Remove file from war with Gradle
Any help is highly appreciated!
Cheers,
d.
---------UPDATE-------------------
Thanx Lance Java for your solution.
As I mentioned in my comment, I faced the problem that the war files were downloaded/extracted during execution time and hence not accessable to define the new tasks at configuration time.
My workaround for this is to use tarTree (with a filter) to access the list of war-files that are not yet extracted. See my code example below:
def warFileSourceTarGz = '...tar.gz'
def nfsLibDir="$buildDir/dependencies/"
def nfsLibDownloadDir="$buildDir/downloadedDependencies/"
// task that downloads & extracts the tar.gz
task fetchNfsDependencies(type: Copy) {
from tarTree(warFileSourceTarGz)
into nfsLibDownloadDir
}
// loop through all war files inside the tar.gz and
// create a task to remove unwanted libraries for each war
task excludeUnwantedJarsFromWars(dependsOn: fetchNfsDependencies){
// access the "remote" tar.gz file to get the list of war-files to loop over
def warFileSource = tarTree(warFileSourceTarGz).matching{
include '*.war'
}
// for every war-file, create an exclude-path
warFileSource.visit { nextWarFile ->
if(nextWarFile.name.endsWith('.war')) {
String taskName = "excludeUnwantedJarsFrom_${nextWarFile.name.replace('.war', '')}"
String nextWarFilePath = nfsLibDownloadDir+"/"+nextWarFile.name
Zip tweakWarTask = tasks.create(name: taskName, type: Zip, dependsOn: fetchNfsDependencies) {
from zipTree(nextWarFilePath)
destinationDir = file(nfsLibDir)
archiveName = nextWarFile.name
// exclude these jars, as they cause classloading problems in our ear deployment.
exclude 'WEB-INF/lib/jcan-optrace*'
}
// hook into build-process
ear.dependsOn(tweakWarTask)
}
}
}
ear.dependsOn(excludeUnwantedJarsFromWars)
I'd create a Zip task per war file and wire all the tasks into the DAG by having assemble depend on them all
FileTree warFiles = fileTree(dir: 'path/to/wars', includes: ['**/*.war'])
warFiles.files.each { File warFile ->
String taskName = "tweakWar${warFile.name.replace('.war', '')}"
Zip tweakWarTask = tasks.create(name: taskName, type: Zip) {
from zipTree(warFile) {
exclude 'path/to/some/file.xml'
}
destinationDir = "$buildDir/tweakedWars"
archiveName = warFile.name
}
// wire the task into the dag
assemble.dependsOn tweakWarTask
}

use root path to file instead of subproject path for zipTree

I've got this project structure
journey\
applications\
desktop\
core\
I've got a task that downloads .zip archive.
task download_redis(type: Download) {
src 'https://github.com/MSOpenTech/redis/releases/download/win-3.2.100/Redis-x64-3.2.100.zip'
dest new File("applications/redis/install", 'Redis-x64-3.2.100.zip')
onlyIfNewer true
}
It saves zip file into applications\redis\install.
Then I've got another task that supposed to extract the content of zip file into applications/redis.
task install_redis(dependsOn: download_redis, type: Copy) {
from zipTree(download_redis.dest)
into 'applications/redis'
}
But I get this error
Cannot expand ZIP 'L:\journey\desktop\applications\redis\install\Redis-x64-3.2.100.zip' as it does not exist.
It seems trying to resolve the path to zip from desktop project, despite it being level higher - a root.
How to set for zipTree to use path from root and not from subproject? (Though both these tasks are inside desktop subproject)
You can access various paths like so:
println project(":applications").projectDir
println project(":desktop").projectDir
// root
println project(":").projectDir
Here is an example :desktop:build.gradle file that uses a spoof zip download. Note the applicationsDir variable. (I'm assuming that you are using the same plugin as the one specified.):
plugins {
id "de.undercouch.download" version "1.2"
}
apply plugin: 'de.undercouch.download'
import de.undercouch.gradle.tasks.download.Download
def applicationsDir = project(":applications").projectDir
task download_redis(type: Download) {
src 'https://github.com/codetojoy/Git_Sandbox/raw/master/tmp/example.zip'
dest new File("${applicationsDir}/redis/install", 'Redis-x64-3.2.100.zip')
onlyIfNewer true
}
task install_redis(dependsOn: download_redis, type: Copy) {
from zipTree(download_redis.dest)
into "${applicationsDir}/redis"
}

Gradle: Not able to run zipTree in doFirst block

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.

Adding file to zip in gradle

I'm currently building a zip in gradle from file referenced in a configuration using the following code:
task makeZip(type: Zip) {
baseName 'libsZip'
from configurations.compile
exclude { it.file in configurations.common.files }
Additionally I want to add an image file (logo.png), located in the same directory of the build.gradle .
How can I achieve this?
You can simply add it with one more from method call like:
task makeZip(type: Zip) {
baseName 'libsZip'
from configurations.compile
from ('logo.png')
exclude { it.file in configurations.common.files }
}

Resources