How to translate gradle jar config in build.gradle into plugin code - gradle

I earlier asked this question about configuring the jar task in a particular way. I now need to translate this into the code in a custom plugin.
The working config in the build.gradle was this:
jar {
exclude "yang"
from ("src/main/resources/yang") {
into ("META-INF/yang")
}
}
This correctly puts classes at the root, but puts the files from "src/main/resources/yang" into "META-INF/yang".
In my custom plugin's "apply" method, I tried doing this in my "project.afterEvaluate()" closure:
Jar jarTask = project.getTasks().getByName("jar")
jarTask.exclude("yang")
jarTask.from(task.yangFilesRootDir)
jarTask.into("META-INF/yang")
From the API doc for "Jar", I couldn't see any other way to do this that "looks like" what I had in the build script.
This doesn't work. It does put the files from "src/main/resources/yang" into "META-INF/yang", but it also puts all of the class files there.

Assuming your plugin is implemented in Groovy, you'll want to move the call to into() to a configuration closure passed to the from() method.
jarTask.from(task.yangFilesRootDir) {
into 'META-INF/yang'
}

Related

How to set the gradle outout folder for the kotlin2JS plugin?

I have a KotlinJs only project which I use official kotlin2js gradle to build, and no problems there.
How to setup the output folder, currently, the building of subproject will result in a build which locates inside the subproject folder, how to set it to somewhere else? I tried:
sourceSets {
main {
kotlin.outputDir = new File(‘./out/‘)
}
}
and
sourceSets {
main.kotlin.outputDir = new File(‘./out/’)
}
No luck.
What I want is to no matter how many subprojects are there, the output folder should be in some path like ./build/projectA and ./build/projectB, rather than all in their own folder. How to do this?
Currently, it's done through the task configuration, namely setting its kotlinOptions.outputFile:
compileKotlin2Js.kotlinOptions.outputFile = "out/output.js"
It's briefly mentioned in the tutorial: Getting Started with Kotlin and JavaScript with Gradle

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'
}
}

Including a second jar file that's not a dependency into a fat onejar

I have a project that only builds the fat onejar file for testing purposes. Thus, there's a separate testing class that I don't want as a dependency to the main source, but I do want it included into the onejar. Odd scenario, I know.
I'm using the com.smokejumperit.gradle.OneJarPlugin plugin (source here), and clearly it gets the list of files to include in the onejar here:
project.task('oneJar', dependsOn:[project.tasks.jar, project.tasks.typedefOneJar]) {
...
inputs.files([jar.outputs.files, project.configurations.getByName("compile"), project.configurations.getByName("runtime")])
jar.output.files is used for publishing, so I don't want a this second jar file being published, and the two project.configurations would define dependencies for the main source jar, and I don't want this second jar to be a dependency of that either.
This second jar file is built with a task:
task integrationJar(type: Jar) {
from sourceSets.integrationTest.output
classifier = 'integration'
}
... so I can access the resulting FileCollection via integrationJar.outputs.files. If there was a clear way to add that to oneJar.input.files, I'd be golden, but I can't figure out how to do that. I've tried something like this:
oneJar {
dependsOn 'integrationJar'
println integrationJar.outputs.files.getAsPath()
inputs.files.add(integrationJar.outputs.files)
println inputs.files.getAsPath()
}
... but the result for the last print is still missing the integration jar file.
Ideas?
I'm not familiar with the implementation of that plugin, but I'd be surprised if inputs.files determined what gets included. (Usually, inputs is just consumed by Gradle's up-to-date check.) I recommend to try the gradle-one-jar plugin, which appears to be more flexible.

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.

Where can I put my custom task class in Gradle

It's easy to write a custom plugin and include it in the build script
apply from: "utilities.gradle"
For test purpose this file is in the same directory as the build.gradle
Calling a task defined in utilities.gradle from build.gradle works without any hassle.
In utilities gradle is also a plugin defined - configuring it from build.gradle just works.
But if I define a custom task in utilities.gradle calling it is no problem but if I want to use that custom taks in build.gradle it says
> Could not find property 'GreetingTask' on root project 'TestGradle'.
utilities.gradle:
task hello(type: GreetingTask)
class GreetingTask extends DefaultTask {
#TaskAction
def greet() {
println 'hello from GreetingTask'
}
}
build.gradle
task hellox(type: GreetingTask)
Ok... I read the documentation here: http://www.gradle.org/docs/current/userguide/custom_tasks.html
It says the custom task is not visible outside...
But then... how to share custom tasks with the team without making a Jar for everything.
What I want is to place the utilities.gradle on a network drive and share it with the other.
pls help
There is a special $rootDir/buildSrc directory which is its own build. All classes that this build produces are available to all build scripts in the "main" build. The buildSrc build has a default build.gradle, but you can add your own. By default, Java classes are expected under src/main/java, and Groovy classes under src/main/groovy. You can read more about buildSrc in the Gradle User Guide.
To share classes across multiple builds, a separate plugin project that publishes a Jar is the way to go.

Resources