get gradle to ignore version number in jar name - gradle

I have a project that has to build about 10 different dummy jars for unit testing. I have a gradle project setup like this
project(':CodeTools_dummydriver-true') {
ext.dummyDriver = true
archivesBaseName = "dummydriver-true"
}
But the problem is the jarfile is still named dummydriver-true-0.0.1.jar. Is there any way I can tell gradle to ignore the standard pattern and please name the output file what I want it to be named? Meaning, without the version number?

The Java plugin defines the jar task to follow the following template for archiveName:
${baseName}-${appendix}-${version}-${classifier}.${extension}
I don't think there's a way to apply a new "naming template", but what you can do is to explicitly set your jar task's archive name, like this. (Also, isn't it a good idea to use the dummyDriver property directly, instead of hardcoding "true" into the archive name?)
archivesBaseName = "dummydriver"
jar.archiveName = "${jar.baseName}-${dummyDriver}.${jar.extension}"
Alternately, set the version property to null or an empty string, like suggested in Circadian's answer, but if you ever want to use the version property for anything, you don't want to destroy it.

For newer gradle you should use:
build.gradle.kts:
tasks.jar {
archiveFileName.set("${project.name}-new-name.jar")
}
build.gradle:
jar.archiveFileName = "new-name.jar"
Because archiveName is deprecated. (You have to specify .jar as well).

Adding a version property and setting its value to an empty string worked for me.
Here is an example:
project(':CodeTools_dummydriver-true') {
ext.dummyDriver = true
archivesBaseName = "dummydriver-true"
version= ""
}
Hope that helps.

Related

accessing fields from non-root project in gradle

this seems like it should be very simple, but I'm stuck! I have a gradle task that zips some files and creates an archive. I want to suffix the name of the archive with the version string from the project I'm in (this is a subproject in a multi-project build)
there's another task in this same build.gradle file that accesses this version field, that I want to access too. it looks like this:
task releasePublishAuto(dependsOn: [tasks.cppApiVersion, rootProject.tasks.releasePublish]) {
doLast {
println("############################################################")
println("# PUBLISHED CPP API WITH VERSION: $version")
println("############################################################")
}
}
you can see it accessing the version variable and printing it using $version. it prints something like # PUBLISHED CPP API WITH VERSION: 1.256.4-SNAPSHOT
now, my task is a zipping task, so it's a bit different:
task zipGeneratedCppClientApi(type: Zip, group: "code generator", dependsOn: [tasks.cppApiVersion, "generateCormorantCPP"]) {
from(fileTree(dir: "$buildDir/generated/cormorant_cpp", include: "**/*"))
archiveFileName = "$buildDir/distributions/generated-cpp-api-$version"
}
I would expect this to create a zipfile named generated-cpp-api-1.256.4-SNAPSHOT but instead i get one named generated-cpp-api-null. As far as I can tell this is because in the context of my zipping task, version refers to the version of the zipping library (or somesuch), not the version of the current project. I've tried instead accessing rootproject.version but that's also null - this isn't the root project but a subproject thereof!
How can I access the version field in this non-root project in gradle?
to clarify: if I remove type:zip from my task, version points to the correct value, but without type:zip it doesnt create a zipfile and so isnt very helpful.
In the context of a Zip task, the version property refers to the AbstractArchiveTask.version property, as you have somehow guessed, and not to the current project version property. As you can see, this version property has been deprecated on AbstractArchiveTask class, maybe to avoid such confusion.
To use project version instead, simply use ${project.version} as in following example.
in your subproject build script:
version="1.0.0"
tasks.register('packageDistribution', Zip) {
println("version from AbstractArchiveTask : $version") // => here, version will be null
println("version from project: ${project.version}") // => here, version will be "1.0.0" as expected
archiveFileName = "my-distribution-${project.version}.zip" // => my-distribution-1.0.0.zip as expected
destinationDirectory = layout.buildDirectory.dir('dist')
from layout.projectDirectory.dir("src/dist")
}

How do you access gradle.ext properties in Plugin Java source code?

I need a property to (one) be available when a plugin is applied and (two) allow for a calculated override value in the settings.gradle file. A project property would be ideal as it can have a default set in gradle.properties:
# gradle.properties
myProp=originalValue
This is great because it can be overrode with a command line argument like -PmyProp=newValue, but I was not able to find a good way to override the property in the settings.gradle file before the build.gradle executes (i.e. before the plugins are applied).
For instance all of these leave rootProject.myProp unaltered at plugin application:
// settings.gradle
rootProject.getProperties.put("myProp", "overrideValue")
settings.ext.myProp = "overrideValue"
settings.extensions.myProp = "overrideValue"
gradle.startParameters.projectProperties.myProp = "overrideValue"
We cannot do any magic in the build.gradle either because no logic can exist before the plugins block:
// build.gradle
plugins {
id 'com.myCompany.myPlugin' version 1.0.0 // 'myProp' must be set by now
}
One workaround I can think of would be to use:
// settings.gradle
gradle.ext.myProp = "overrideValue"
... but there doesn't seem to be a good way to access gradle.ext properties in Java source code (for a plugin), or is there?
This seems to work for the gradle.ext.myProp use case, but it is surprising to me that the only workable approach is to cast the Gradle object to an ExtensionAware object:
// MyPlugin.java
String myProp = (String) project.getRootProject().getProperties().getOrDefault("myProp", null);
Gradle gradle = project.getRootProject().getGradle();
if ((myProp == null) && (gradle instanceof ExtensionAware)) {
ExtensionAware gradleExtensions = (ExtensionAware) gradle;
myProp = (String) gradleExtensions.getExtensions().getExtraProperties().get("myProp");
}
It seems like what I'm trying to do should be commonplace, so is there a better way like solely using project properties?
If so, then how do you change the values in the settings.gradle file?
This is probably not what you’re looking for but maybe it still helps: have you considered an initialization script? In such a script it is possible to override a project property.
Example:
$ ./gradlew -PmyProp=originalValue properties | grep myProp
myProp: originalValue
$ ./gradlew -PmyProp=originalValue -I init.gradle properties | grep myProp
myProp: overrideValue
… where init.gradle is the following:
allprojects {
project.ext.myProp = 'overrideValue'
}
Note that there are also other ways of specifying the init script.

Gradle/Groovy refer to "file-wide/global" variable from inside block

In my build file I have the following line:
version = '1.1.2'
I want to make an executable "fat jar" using Shadow Jar (see my answer here) and then copy this to another directory (see answer here). But I want to incorporate the project's version number into the name of the jar file so as not to overwrite the existing version.
The Shadow Plugin User Guide explains how to set the name:
shadowJar {
baseName = 'shadow'
classifier = null
version = "7.7.7"
}
... but how might I set the variable version here to use the outer (file-wide/global...) variable version?
In a gradle script, there's a Project instance in scope which everything delegates to. When you say version = '1.1.2' it's actually invoking
getProject().setVersion('1.1.2')
In your shadowJar closure there's a version higher up in the scope which is hiding the project version. So you can do
shadowJar {
version = project.version
...
}

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.

OSGi bundle build issue in Gradle

I have a simple use case of building an OSGi bundle using Gradle build tool. The build is successful if there are java files present in the build path, but it fails otherwise.
I am using 'osgi' plugin inside the gradle script and trying to build without any java files. The build always fails with following error:
Could not copy MANIFEST.MF to
I am sure there must be some way to do it in Gradle but not able to fine. Any idea what can be done to resolve this depending on your experience.
I ran into this today as well, and #Peter's fix didn't work for me (I hadn't applied the java plugin in the first place...). However, after hours of Googling I did find this thread, which helped me find the problem.
Basically, it seems that the error occurs (as Peter stated) when no class files are found in the jar - my guess is because the plugin then cannot scan the classes for package names on which to base all the Import and Export information.
My solution was to add the following to the manifest specification:
classesDir = theSourceSet.output.classesDir
classpath = theSourceSet.runtimeClasspath
In my actual build code, I loop over all source sets to create jar tasks for them, so then it looks like this:
sourceSets.each { ss ->
assemble.dependsOn task("jar${ss.name.capitalize()}", type: Jar, dependsOn: ss.getCompileTaskName('Java')) {
from ss.output
into 'classes'
manifest = osgiManifest {
classesDir = ss.output.classesDir
classpath = ss.runtimeClasspath
// Other properties, like name and symbolicName, also set based on
// the name of the source set
}
baseName = ss.name
}
}
Running with --stacktrace indicates that the osgi plugin doesn't deal correctly with the case where both the osgi and the java plugins are applied, but no Java code is present. Removing the java plugin should solve the problem.
I had the same issue also when java code was present.
Adding these two lines to the osgiManifest closure fixed the problem:
classesDir = sourceSets.main.output.classesDir
classpath = sourceSets.main.runtimeClasspath
-- erik

Resources