Copying Files From One Zip File Into Another In Gradle - gradle

We are working on migrating to Gradle from Maven. Unfortunately we still have a couple of War overlays to deal with.
As a work-around I am trying to copy the contents of one war file into another.
This is what I have so far:
task overlayWars (dependsOn: war) << {
// Get the source war files to copy the contents from...
def dependencyWars = configurations.runtime.filter { it.name.endsWith ('.war') }
dependencyWars.each { dependentWar ->
// Get the products, ie the target war file...
war.outputs.files.each { product ->
println "Copying $dependentWar contents into $product"
copy {
from { zipTree (dependentWar) }
into { zipTree (product)} // this seems to be the problem
include 'WEB-INF/classes/**/*.class'
include 'WEB-INF/jsp/**/*.jsp'
}
}
}
}
When into { zipTree (product)} is a file (like file ('tmp/whatever')) this works fine. When specifying another zip file (the target war file) it fails with the error:
Converting class
org.gradle.api.internal.file.collections.FileTreeAdapter to File using
toString() method has been deprecated and is scheduled to be removed
in Gradle 2.0. Please use java.io.File, java.lang.String,
java.net.URL, or java.net.URI instead.
If anyone has suggestions on this specifically, or a better way to "overlay" war files, I'd really appreciate it!

After chasing down a couple of different angles, I ended up with this:
war {
configurations.runtime.filter { it.name.endsWith ('.war') }.each {
from zipTree (it).matching {
include 'WEB-INF/classes/**/*.class'
include 'WEB-INF/jsp/**/*.jsp'
include 'images/**'
}
}
}
Basically I am just including filtered contents of any .war dependencies in the product. Being an alteration to the standard war task, the dependency tree is kept clean. It seems to work for us so far...

In case you are trying to merge Wars here, you can't do that with a Copy task/method. You'll have to use a Zip task (there is no equivalent method). In case you want to merge into an existing War, the way to do this is existingWar.from { zipTree(otherWar) }.

Related

Filter class files from compiled sourcesets to be added in a JAR in Gradle/Groovy

I'm trying to include the compiled .class files from Project1 into the jar for Project2 since my project structure requires it to be done. For that, in the build.gradle for Project2, I write :
jar {
from project(':Project1').sourceSets.main.output.classesDir
}
Which successfully does what I had to do. But, I now want to filter some of the classes that are added based on path and/or some pattern. For example, to include only delegate files, I tried this :
jar {
from project(':Project1').sourceSets.main.output.classesDir {
include '**/*Delegate*.class'
}
}
But unfortunately it doesn't work. Is there a way to achieve this in Gradle/Groovy?
Using Gradle 2.12, the following works for me (this is build.gradle for Project 2):
task myBuild(type: Jar) {
baseName "myjar"
from project(':Project1').sourceSets.main.output.classesDir,
{ include "**/*Delegate*.*" }
}
From the doc for Jar.from, note that it takes 2 arguments (hence, the comma is used).
Thanks Michael
Although I got my answer as well, I was just missing a parantheses. The correct and working code goes something like this :
jar {
from (project(':Project1').sourceSets.main.output.classesDir) {
include '**/*Delegate*.class'
}
}

Copy files over before jarring

I can't get my script to wait until libraries are copied over to 'src/main/resources/libs' before it starts to jar up everything. The files are copied over but the jar task I think is not waiting until the files are copied over? Because they are not added to my jar. Unless I run script again :/ How to fix this?
task copyDependencies(type: Copy) {
from configurations.myLib
into 'src/main/resources/libs'
}
jar.dependsOn 'copyDependencies'
jar {
manifest {}
}
To get the execution order right, processResources would have to depend on copyDependencies. However, you shouldn't copy anything into src/main/resources. Instead, the libraries should be included directly in the Jar, without any intermediate steps:
jar {
into("libs") {
from configurations.myLib
}
}
This assumes that there is some custom process or class loader in place that makes use of the libraries in the Jar's libs directory. A standard JVM/class loader will ignore them.

Gradle replacing Maven assembly plugin

I'm fairly new to Gradle, and trying to port an existing Maven pom.xml that makes extensive use of maven-assembly-plugin to create various zip files.
In the example below, I'm getting files from various subdirectories (with particular extensions), and then mapping them in a flat structure to a ZIP file.
task batchZip(type: Zip) {
from fileTree('src/main/sas') {
include('**/*.sas')
include('**/*.ds')
}.files
}
This puts all the files in the root of the zip. What I ideally need though, is for the files to live under a particular path in the root of the zip, e.g. /shared/sas.
Is there a way to do this without first copying all the files to a local directory and then zipping that up?
task batchZip(type: Zip) {
into('shared/sas') {
from { fileTree('src/main/sas').files }
include('**/*.sas')
include('**/*.ds')
}
}
Have a look at the docs. It seems that if You specify appropriate into You'll get the result You're looking for.

Gradle embedded Project

Is it possible to embed multiple projects in a single build.gradle?
Something along the lines of:
project projX {
task a << {
}
}
project projY {
task a << {
}
}
Both within the same build.gradle. Is this possible?
I am asking this because I have multiple projects with equivalent task names which I want to execute from the root project, e.g.
gradle a
However the projects contain only automation tasks, which require no source files or resource files at all. Creating subdirectories just for the build.gradle files to be stored seems very ugly to me.
I could live with a solution with different .gradle files for each project, such as: build.gradle (root)
projA.gradle, projB.gradle within the same directory, however embedding project objects in the root build.gradle seems like the better option, if it is available.
project(":projX") { ... }
project(":projY") { ... }
Note that you still need a settings.gradle.
PS: It's not clear to me why you would want multiple projects in your case.

How to expand property references in jar resources?

I'm using Gradle to build a jar containing an xml file in META-INF. This file has a row like
<property name="databasePlatform" value="${sqlDialect}" />
to allow for different SQL databases for different environments. I want to tell gradle to expand ${sqlDialect} from the project properties.
I tried this:
jar {
expand project.properties
}
but it fails with a GroovyRuntimeException that seems to me like the Jar task attempts to expand properties in .class files as well. So then I tried
jar {
from(sourceSets.main.resources) {
expand project.properties
}
}
which does not throw the above exception, but instead results in all resources being copied twice - once with property expansion and once without. I managed to work around this with
jar {
eachFile {
if(it.relativePath.segments[0] in ['META-INF']) {
expand project.properties
}
}
}
which does what I want, since in my use case I only need to expand properties of files in the META-INF directory. But this feels like a pretty ugly hack, is there a better way to do this?
I stumbled across this post in a thread about a different but closely related issue. Turns out you want to configure the processResources task, not the jar task:
processResources {
expand project.properties
}
For some reason, though, I did have to clean once before Gradle noticed the change.
In addition to #emil-lundberg 's excellent solution, I'd limit the resource processing to just the desired target file:
build.gradle
processResources {
filesMatching("**/applicationContext.xml") {
expand(project: project)
}
}
An additional note: if the ${...} parentheses are causing "Could not resolve placeholder" errors, you can alternatively use <%=...%>. N.B. tested with a *.properties file, not sure how this would work for an XML file.
I've had similar problems migrating from maven to gradle build. And so far the simplest/easiest solution was to simply do the filtering yourself such as:
processResources {
def buildProps = new Properties()
buildProps.load(file('build.properties').newReader())
filter { String line ->
line.findAll(/\$\{([a-z,A-Z,0-9,\.]+)\}/).each {
def key = it.replace("\${", "").replace("}", "")
if (buildProps[key] != null)
{
line = line.replace(it, buildProps[key])
}
}
line
}
}
This will load all the properties from the specified properties file and filter all the "${some.property.here}" type placeholders. Fully supports dot-separated properties in the *.properties file.
As an added bonus, it doesn't clash with $someVar type placeholders like expand() does. Also, if the placeholder could not be matched with a property, it's left untouched, thus reducing the possibility of property clashes from different sources.
here is what worked for me (Gradle 4.0.1) in a multi-module project:
in /webshared/build.gradle:
import org.apache.tools.ant.filters.*
afterEvaluate {
configure(allProcessResourcesTasks()) {
filter(ReplaceTokens,
tokens: [myAppVersion: MY_APP_VERSION])
}
}
def allProcessResourcesTasks() {
sourceSets*.processResourcesTaskName.collect {
tasks[it]
}
}
and my MY_APP_VERSION variable is defined in top-level build.gradle file:
ext {
// application release version.
// it is used in the ZIP file name and is shown in "About" dialog.
MY_APP_VERSION = "1.0.0-SNAPSHOT"
}
and my resource file is in /webshared/src/main/resources/version.properties :
# Do NOT set application version here, set it in "build.gradle" file
# This file is transformed/populated during the Gradle build.
version=#myAppVersion#
I took your first attempt and created a test project. I put a pom file from a jenkins plugin in ./src/main/resources/META-INF/. I assume it is a good enough xml example. I replaced the artifactId line to look like the following:
<artifactId>${artifactId}</artifactId>
My build.gradle:
apply plugin: 'java'
jar {
expand project.properties
}
When I ran gradle jar for the first time it exploded because I forgot to define a value for the property. My second attempt succeeded with the following commandline:
gradle jar -PartifactId=WhoCares
For testing purposes I just defined the property using -P. I'm not sure how you are trying to define your property, but perhaps that is the missing piece. Without seeing the stacktrace of your exception it's hard to know for sure, but the above example worked perfectly for me and seems to solve your problem.

Resources