How do I copy a file into my WAR based on profile? - gradle

I’m using Gradle 2.7 on Mac Yosemite. I have the following files:
src/main/environment/dev/context.xml
src/main/environment/qa/context.xml
src/main/environment/prod/context.xml
What I would like is if I run a build gradle -Pqa build, the appropriate context.xml file above is copied into my WAR (into the WEB-INF/classes directory is fine). How do I set this up with gradle?

There're many ways of solving the problem. You can configure sourceSets, or include or exclude particular resources when building war file. You can also have single context.xml and perform resource filtering with ReplaceTokens filter.
I've chosen sourceSets:
apply plugin: 'war'
ext.env = project.hasProperty('env') ? project.env : 'dev'
sourceSets {
main {
resources {
srcDir "src/main/environment/$env"
}
}
}
The trick is to include/process only the env being passed. If no env is passed dev will be picked for further processing. Have a look a the demo.

You would have to do that using the environment variable. Have the system properties in a file. Read them in the build.gradle and based on it include the context.xml into the war.

Related

Gradle task for updating a file inside a WAR file

I have SpringBoot project that generates both a deployable and an executable WAR file using the SpringBoot Gradle plugin. I want to update a .properties file inside of both WAR files. My files look like this:
build/libs/my-app-1.0.0.war
...
/WEB-INF/classes/file.properties
...
build/libs/my-app-1.0.0-boot.war
...
/WEB-INF/classes/file.properties
...
I want to update a single key inside the properties file or completely replace the file. Either solution would work.
These are the versions:
Gradle 6.2.2
SpringBoot 2.2.5.RELEASE
I was able to solve the problem by
modifying the answer linked by #Lesiak in the comments as follows:
processResources {
filesMatching('**/file.properties') {
filter(org.apache.tools.ant.filters.ReplaceTokens,
tokens: [replace-token: project.property('replace-value').toString()])
}
}

Make a simple JAR in gradle

I am new to gradle builds. I wrote a custom service for cloudera manager which needs to build a JAR file with few directories. It is a simple archive file with few directories(descriptor, images and scripts). I created it with below jar command manually.
jar -cf CSDNAME.jar descriptor images scripts
Now I want to include this as part of gradle build for which I need to write a task. I searched online where I found java related stuff which is not required in my case. Can someone help with this?
That's a code snippet using the kotlin dsl. It's based on the JAR task of the java plugin.
plugins {
java
}
tasks.jar {
doFirst {
archiveBaseName.set("CSDNAME") // By default the JAR will have the project name
from("content") // source folder where you have your content
}
}
N.B: If you already have a build file, you will need to change its extension to .kts, else you'll need of course to create one.

Gradle multi-project with shared logging config

Is there a standard way to share a logging config (for log4j or logback for example) across all sub projects in a gradle project layout?
What I do right now is put a copy of logback.xml (or log4j.properties) in src/main/resources in each sub-project but this results in a lot of unnecessary duplication of this config file
This can be easily overcome using multiple working sets in gradle.
Add a new folder in the root of the project, example "shared-resources" put our configs inside it, and simple add the following line to your build.gradle on the sub-project
sourceSets {
main {
resources {
srcDirs = ["src/main/resource", "../shared-resources"]
}
}
}
This should add both files to your jar file.
An example can be find in github
Create a shared util module containing your Log4j2 configuration in its src/main/resources directory.
Then import the util module into others.
dependencies {
compile project(":util");
}
I also use the util module for re-usable Java code, not just for once-off configuration of Log4j2.

Gradle - Add folder to Eclipse classpath

I am migrating a legacy application from Ant to Gradle. The requirement is to build a zip file with a certain folder structure which is used by the deployment team. I am able to create the zip file in the correct format, so-far-so-good.
I am able to open the project in Eclipse, but cannot run it. In Eclipse (and IntelliJ) I need src/main/conf to be added to Eclipse's classpath, but not be included in the JAR (e.g. if I were to run gradle jar).
This is how the project is currently structured:
src
/main
/java
/com
/example
/App.java
/resources
/applicationConfiguration.xml
/conf
/dev.properties
/staging.properties
/prod.properties
How can I add the conf folder to Eclipse's classpath so that it is not included in the JAR that Gradle creates?
Given the limitations of Gradle's EclipseClasspath API, the most straightforward solution I can think of is to declare src/main/conf as another source directory:
sourceSets.main.java.srcDir "src/main/conf"
As long as the directory doesn't contain any Java files, this won't affect the outcome of the Gradle build. However, the directory will show up as a source directory in Eclipse, and its properties files will therefore be copied into the Eclipse output directory.
Another tip. If you need it to run in Eclipse WTP, then I set the sourceDirs property of eclipse.wtp.component:
eclipse {
project {
natures 'org.eclipse.wst.common.project.facet.core.nature',
'org.eclipse.wst.common.modulecore.ModuleCoreNature',
'org.eclipse.wst.jsdt.core.jsNature'
name 'blah-blah'
}
wtp {
facet {
facet type: 'fixed', name: 'wst.jsdt.web'
facet name: 'java', version: '1.7'
facet name: 'jst.web', version: '3.0'
facet name: 'wst.jsdt.web', version: '1.0'
}
component {
sourceDirs = new HashSet([
new File(project.getProjectDir().getAbsolutePath() + "/src/main/java"),
new File(project.getProjectDir().getAbsolutePath() + "/src/main/resources"),
new File(project.getProjectDir().getAbsolutePath() + "/src/main/conf")
])
}
}

Gradle dependency destination on non-jar config file

I can create a dependency to something other than a jar file like this:
dependencies {
compile files("../other-project/config.txt")
}
The above works fine, except that config.txt ends up in the WEB-INF/lib folder of my war file. Instead I need it to be in WEB-INF/classes in the war file, and in src/main/resources for jettyRun.
How can I control where the dependency ends up? Or am I going about this the wrong way?
I can also solve this with a copy task, but this really is a dependency in that I don't need the file updated unless it changes. An unconditional copy would work, but I'd rather do this the right way.
The war task (as configured by the war plugin) puts dependencies into WEB-INF/lib, the web project's own code/resources into WEB-INF/classes, and web app content (which by default goes into src/main/webapp) into WEB-INF. Other content can be added by explicitly configuring the war task. For example:
war {
into("WEB-INF/classes") {
from "../other-project/config.txt"
}
}
One way to make this work with embedded Jetty (though maybe not the most convenient during development) is to use jettyRunWar instead of jettyRun. Another solution that comes to mind, particularly if the content to be added resides in its own directory, is to declare that directory as an additional resource directory of the web project (sourceSets.main.resources.srcDir "../other-project/someResourceDir"). This is in fact an alternative to configuring the war task. If the web project already has a dependency on the other project, you could instead configure an additional resource directory for that project.
Let's say you have configured a multi-project build with the following directory and file structure:
/combined-war
/main-project
/src
/webapp
/WEB-INF
web.xml
build.gradle
/other-project
/resources
/WEB-INF
/classes
config.txt
build.gradle
build.gradle
In order to allow jettyRun to combine the contents of the webapp directory from main-project with the contents of the resources directory in other-project you need to add a workaround to your build.gradle of main-project (I've adapted the one posted by the user siasia on gist).
Adding the same directory content to the war file is quite simple and is documented in the Gradle User Guide and and the DSL reference.
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'jetty'
import org.gradle.api.plugins.jetty.internal.JettyPluginWebAppContext
def newResourceCollection(File... resources) {
def script = '''
import org.mortbay.resource.ResourceCollection
new ResourceCollection(resources)
'''
def shell = new GroovyShell(JettyPluginWebAppContext.class.classLoader)
shell.setProperty("resources", resources as String[])
return shell.evaluate(script)
}
jettyRun.doFirst {
jettyRun.webAppConfig = new JettyPluginWebAppContext()
jettyRun.webAppConfig.baseResource = newResourceCollection(
// list the folders that should be combined
file(webAppDirName),
file("${project(':other-project').projectDir}/resources")
)
}
war {
from("${project(':other-project').projectDir}/resources")
}
Whenever you execute gradle jettyRun a new ResourceCollection is created that combines the given directories. Per default Jetty locks (at least on Windows) all the files it's serving. So, in case you want to edit those files while Jetty is running take a look at the following solutions.
Update
Since other-project in this case is not another Gradle project the two tasks in build.gradle should look like that:
jettyRun.doFirst {
jettyRun.webAppConfig = new JettyPluginWebAppContext()
jettyRun.webAppConfig.baseResource = newResourceCollection(
file(webAppDirName),
file("$projectDir/../other-project/resources")
)
}
war {
from("$projectDir/../other-project/resources")
}
I'm not aware of any solution that adds only one file (e.g. config.txt). You'll always have to add a complete directory.
As I mentioned above, it's simple enough to do an unconditional copy that solves the problem. Again, not the question I originally asked. But here's my solution that works for both war and jettyRun tasks:
processResources.doFirst {
copy {
from '../other-project/config.txt'
into 'src/main/resources'
}
}

Resources