Gradle Zip task to do multiple sub-trees? - java

We're trying to build up a minorly complicated Zip file in Gradle from multiple filesystem source trees, but no matter how many into specifications we give, it all puts them in the same one. Is this possible to do in Gradle?
build/libs/foo.jar --> foo.jar
bar/* --> bar/*
We're getting this instead:
build/libs/foo.jar --> bar/foo.jar
bar/* --> bar/*
Using this:
task installZip(type: Zip, dependsOn: jar) {
from('build/libs/foo.jar').into('.')
from('bar').into('bar')
}
Any help would be appreciated.
EDIT: Gradle 1.0-milestone-3

Try this:
task zip(type: Zip) {
from jar.outputs.files
from('bar/') {
into('bar')
}
}
First... the jar should be in the root / of the zip (which seems to be what you want). Second, by specifying the from jar.outputs.files, there is an implicit dependsOn on the jar task, so this shows another way of accomplishing what you want. Except with this approach if the jar name changes over time it doesn't matter. Let me know if you need additional help.

Apparently the comments to an answer will not allow for a convenient way to show more code... or it isn't obvious :) I have a project which is for a client... so I can't share the full project / build file. Here is what I can share (I changed the project specific acron to XXX):
task zip(type: Zip) {
from jar.outputs.files
from('scripts/') {
fileMode = 0755
include '**/runXXX.sh'
include '**/runXXX.bat'
}
from('lib/') {
include '**/*.jar'
into('lib')
}
from('.') {
include 'xxx.config'
}
}
This creates a zip with the project jar in the root of the zip. Copies the scripts from a directory to the root, copies the config file to the root and creates a directory in the root of the zip named /lib and copies all the jars from the project /lib to the zip/lib.

This answer does not directly answer the question but I guess this would help someone who writes 'Gradle Plugins'
final Zip zipTask = project.getTasks().create(taskName, Zip.class);
final Action<? super CopySpec> cp1 = (p) -> {
p.include("**/Install_*.xml", "**/Install.xml").into(WORKING_DIR_1);
};
final Action<? super CopySpec> cp2 = (p) -> {
p.include("*Terminology*.xml").into(WORKING_DIR_2);
};
zipTask.from(projectDir + "/Release", cp1);
zipTask.from(projectDir + "/Release", cp2);

Related

How to access version of my project in build.gradle from a Java class

I'm quite new to Gradle so the answer might be simple, so I apologize if the answer is simple: I have a testing tool that needs to fetch it's version and compare it to the version of the application it is testing. However , the version of my tool is in my build.graddle as
version '1.0'
I tried different way to access it ( such as) :
task generateSources {
File outDir
outDir = file("$buildDir/classes/test/tests/Version.java")
doFirst {
outDir.exists() || outDir.mkdirs()
new File(outDir).write("public class Version { public static final String VERSION = \"$project.version\"; }")
}
}
compileJava.dependsOn generateSources
compileJava.source generateSources.outputs.files, sourceSets.main.java
I found this piece of code to output the version to another java file, but I fail to see how I'd be able to retrieve that info afterwards ( I mean, my tests are defined in src and I would need to point to a file that doesn't exist at compilation -- correct me if I'm wrong here).
Any idea on how I could accomplish this task?
First of all, you are trying to create java source file in your build/classes (it should contain compiled classes, not sources) directory, but you have to do it in your sources, otherwise it won't be compiled. And if you need this new class to be vailable not for tests, then use src/main/java, not src/test/java/
But anyway, I suppose for your case it's much easier to use some properties file for that and replace some token within it during build. That will allow you to make some static logic to get this property value and use it yet before running the build. So all you need is:
1- to have some properties file in your resources src/main/resources (for example app.properties), where should version variable be stored, with it's value like APP_VERSION_TOKEN
version=%APP_VERSION_TOKEN%
2- configure you Gradle processResources to replace tokens, something like this:
processResources {
filesMatching('**/app.properties') {
filter {
it.replace('%APP_VERSION_TOKEN%', version)
}
}
}
3- make some method to read this file and return the value of the property and use it where you need.
And that's all. For unit tests you can have another file with the same name under src/test/resource with the unchanging value you need for testing.

Gradle : Exclude certain files from packaging (jar) using annotations

I am looking for a solution to exclude certain files marked with a particular annotation to be packaged in jar (can be compiled but not part of jar created).
I have tried the following steps
Create a ClassLoader using : sourceSets.main.output + configurations.runtime
Check recursively within the compiled classes, use ClassLoader.loadClass to load the class and check if annotation is present (Class.isAnnotationPresent)
Any pointers would be helpful.
I was able to implement this long time back but forgot I had posted the question here.
The solution I used to was actually quite simple -
Using gradle jar task -
jar {
excludes = excludedFiles(sourceSets.main.allSource.files)
baseName = artifactName
version = artifactVersion
}
And define the excludedFiles function to look up the files in the source directory provided -
def excludedFiles(Collection<File> files) {
List<String> classes = new ArrayList<>()
files.each { file ->
if (file.isDirectory()) {
excludedFiles(Arrays.asList(file.listFiles()))
}
else {
if (file.text.contains("#YourAnnotation") && file.text.contains("import foo.bar.YourAnnotation")) {
classes += getClassName(file.absolutePath)
}
}
}
return classes
}
Hope this helps.

Gradle task replace string in .java file

I want to replace few lines in my Config.java file before the code gets compiled. All I was able to find is to parse file through filter during copying it. As soon as I have to copy it I had to save it somewhere - thats why I went for solution: copy to temp location while replacing lines > delete original file > copy duplicated file back to original place > delete temp file. Is there better solution?
May be you should try something like ant's replaceregexp:
task myCopy << {
ant.replaceregexp(match:'aaa', replace:'bbb', flags:'g', byline:true) {
fileset(dir: 'src/main/java/android/app/cfg', includes: 'TestingConfigCopy.java')
}
}
This task will replace all occurances of aaa with bbb. Anyway, it's just an example, you can modify it under your purposes or try some similar solution with ant.
To complement lance-java's answer, I found this idiom more simple if there's only one value you are looking to change:
task generateSources(type: Copy) {
from 'src/replaceme/java'
into "$buildDir/generated-src"
filter { line -> line.replaceAll('xxx', 'aaa') }
}
Caveat: Keep in mind that the Copy task will only run if the source files change. If you want your replacement to happen based on other conditions, you need to use Gradle's incremental build features to specify that.
I definitely wouldn't overwrite the original file
I like to keep things directory based rather than filename based so if it were me, I'd put Config.java in it's own folder (eg src/replaceme/java)
I'd create a generated-src directory under $buildDir so it's deleted via the clean task.
You can use the Copy task and ReplaceTokens filter. Eg:
apply plugin: 'java'
task generateSources(type: Copy) {
from 'src/replaceme/java'
into "$buildDir/generated-src"
filter(ReplaceTokens, tokens: [
'xxx': 'aaa',
'yyy': 'bbb'
])
}
// the following lines are important to wire the task in with the compileJava task
compileJava.source "$buildDir/generated-src"
compileJava.dependsOn generateSources
If you do wish to overwrite the original file, using a temp file strategy, the following will create the filtered files, copy them over the original, and then delete the temp files.
task copyAtoB(dependsOn: [existingTask]) {
doLast {
copy {
from("folder/a") {
include "*.java"
}
// Have to use a new path for modified files
into("folder/b")
filter {
String line ->
line.replaceAll("changeme", "to this")
}
}
}
}
task overwriteFilesInAfromB(dependsOn: [copyAtoB]) {
doLast {
copy {
from("folder/b") {
include "*.java"
}
into("folder/a")
}
}
}
// Finally, delete the files in folder B
task deleteB(type: Delete, dependsOn: overwriteFilesInAfromB) {
delete("folder/b")
}
nextTask.dependsOn(deleteB)

How to copy files from a parent project into a sub project with gradle

I'm trying to share common static files among multiple subprojects in gradle. My project structure is as follows:
ParentProject
+ subProject1War/
+ subProject1War/
+ src/main/webapp/WEB-INF/
+ css/
+ subProject1/
+ subProject2/
+ common/
I cannot for the life of me figure out how to copy ParentProject's "common" and "subProject1" into subProject1War.
Can anyone provide guidance?
You can define a copy task for that in subProject1War/build.gradle and then make the relevant tasks (probably compileJava or processResources) dependent on it so the common files will be available for these tasks during build.
If you'd like all the files under common and subProject1 to be located under subProject1War/src/css then you can define the following task:
task copyCommon(type: Copy) {
def cssLib = new File(rootDir, "src/css")
from "$cssLib/common"
from "$cssLib/subProject1"
into "src/css"
}
If you want to keep the common and subProject1 folders under subProject1War/src/css then your task would look like:
task copyCommon(type: Copy) {
from new File(rootDir, "src/css")
include "common/**"
include "subProject1/**"
into "src/css"
}

Gradle: Create a jar with no classes, only resources

I'm trying to create a group of four jars with the following pattern (each jar has its own project. helpRootDir is shared between all four jars. If somebody knows of a way to make one task that does all four, that'd be awesome)
def helpRootDir = 'runtime/datafiles/help/'
project(':schedwinclihelp') {
def helpDir = 'schedwincli'
//Include no classes. This is strictly a resource jar
sourceSets.main.java {
exclude 'com/**'
}
jar {
from '${helpRootDir}/${helpDir}'
include '**/*.*'
}
}
Anyway as you can see from the above, I want no classes in the jar, and that's working. Unfortunately, all I'm actually getting in the jar is a MANIFEST.MF file. None of the files in the jar definition are getting added. I want the full file tree in ${helpRootDir}/${helpDir} added to the root of the jar. How do I accomplish this?
Figured out I was referencing my variables incorrectly.
The correct syntax is:
def helpRootDir = 'runtime/datafiles/help/'
project(':schedwinclihelp') {
def helpDir = 'schedwincli'
//Include no classes. This is strictly a resource jar
sourceSets.main {
java {
exclude 'com/**'
}
resources {
srcDir helpRootDir + '/' + helpDir
}
}
}
Note srcDir helpRootDir + '/' + helpDir rather than '${helpRootDir}/${helpDir}'. Also, I just made my help dir a resource dir and let the java plugin do its thing automatically.
The following task will create a JAR file named resources.jar with main resource files only (those are placed under src/main/resoures directory).
Kotlin DSL:
tasks {
task<Jar>("resourcesJar") {
from(sourceSets["main"].resources)
archiveFileName.set("resources.jar")
}
}
Groovy DSL:
tasks.create("resourcesJar", Jar.class) {
from sourceSets.main.resources
archiveFileName = "resources.jar"
}

Categories

Resources