localGroovy method within plugin groovy code - gradle

In my plugins, I am always trying to add Groovy to Java. Now this code works just fine when in a build.gradle file, but when I move it to a plugin groovy file so I can compile it and distribute it, it says it can't find the method localGroovy(). What's the correct syntax to call the localGroovy() method here?
project.with {
plugins.withType(JavaPlugin) {
//noinspection GroovyAssignabilityCheck
configurations.all {
resolutionStrategy {
force localGroovy()
}
}
}
}

The method localGroovy() is defined in the DependencyHandler interface. I don't know where in your build script you were using the above code snippet, but you would need to be in the scope of a DependencyHandler to access this method. However, in your plugin, you could just use the DependencyHandler under projects.dependencies:
[...]
resolutionStrategy {
force project.dependencies.localGroovy()
}
[...]
Please note, that I did not test this code and it relies on your statement that the used method force(...) can handle whatever Dependency implementation is returned by localGroovy().
According to the docs, the force(...) method can handle the following inputs:
String in a format of: 'group:name:version', for example: 'org.gradle:gradle-core:1.0'
instance of ModuleVersionSelector
any collection or array of above will be automatically flattened
As long as the Dependency returned by localGroovy() implements the ModuleVersionsSelector interface (e.g. as ExternalDependency), the solution above should work like a charm.

Related

Not able to exclude dependency gradle

I need to exclude slf4j dependency from io.confluent:kafka-schema-registry:5.3.0 . I have tried using
implementation ('io.confluent:kafka-schema-registry:5.3.0') {
exclude(group='org.slf4j',module='slf4j-loh4j12')
}
But i keep getting an error
Cannot set the value of read-only property 'group' for DefaultExternalModuleDependency{group='io.confluent', name='kafka-schema-registry', version='5.3.0', configuration='default'} of type org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency.
Can anyone please tell me how to achieve this. I have tried multiple way but not able to do it
The syntax for exclude() is incorrect. You must use : instead of =. exclude() takes a Map as input, thus, in Groovy DSL, it must be written as:
implementation ('io.confluent:kafka-schema-registry:5.3.0') {
exclude(group: 'org.slf4j', module: 'slf4j-log4j12')
}

Where to put gradle dependencies block in kotlin native project generated by Intellij IDEA?

I'm trying to make my first app in Kotlin Native. I want to add TornadoFX to my freshly created project.
I need to add a dependency according to TornadoFX guide
dependencies {
compile 'no.tornado:tornadofx:x.y.z'
}
The issue is - I cant figure out where exactly do I put it.
This is my build.gradle contents (generated by IntelliJ IDEA):
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.3.60'
}
repositories {
mavenCentral()
}
kotlin {
// For ARM, should be changed to iosArm32 or iosArm64
// For Linux, should be changed to e.g. linuxX64
// For MacOS, should be changed to e.g. macosX64
// For Windows, should be changed to e.g. mingwX64
mingwX64("mingw") {
binaries {
executable {
// Change to specify fully qualified name of your application's entry point:
entryPoint = 'sample.main'
// Specify command-line arguments, if necessary:
runTask?.args('')
}
}
}
sourceSets {
// Note: To enable common source sets please comment out 'kotlin.import.noCommonSourceSets' property
// in gradle.properties file and re-import your project in IDE.
mingwMain {
}
mingwTest {
}
}
}
// Use the following Gradle tasks to run your application:
// :runReleaseExecutableMingw - without debug symbols
// :runDebugExecutableMingw - with debug symbols
Places I tried:
1. top level
> Could not find method compile() for arguments [no.tornado:tornadofx:1.7.19] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
2. inside kotlin {}
> Could not find method compile() for arguments [no.tornado:tornadofx:1.7.19] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
3. inside mingwMain{}
> Could not find method compile() for arguments [no.tornado:tornadofx:1.7.19] on object of type org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinDependencyHandler.
Also, when put inside mingwMain, the compile line gets highlighted with a notice 'compile' cannot be applied to '(java.lang.String)'
For the Kotlin multiplatform plugin, the dependency block should go into each source set. However, there is no type called compile. Rather, you can use implementation or one of the other types which you can read about in the documentation.
Example:
sourceSets {
mingwMain {
dependencies {
implementation 'no.tornado:tornadofx:x.y.z'
}
}
}
BTW, why are you using the Groovy DSL and not the Kotlin DSL if you are writing a Kotlin project? :-)
As it was pointed out by this comment we cannot use TornadoFX in Kotlin Native, so I was doing everything wrong since the beginning, and this is not really a gradle issue.

Dev mode dependency for gradle in IDEA

I want to add dependency on spring-boot-devtools but only for development.
I try to achieve this by having this snippet in my build.gradle:
if (project.hasProperty('use-spring-boot-devtools')) {
compile 'org.springframework.boot:spring-boot-devtools'
}
Then I can define in my ~/.gradle/gradle.properties
use-spring-boot-devtools = true
Unfortunately this doesn't work when I run import project in IDEA. I would like to use answer to related question but still can't figure out how to define environment variable that will affect gradle inside IDEA.
Do not use hyphens to concat your key in the gradle.properties. Instead define it in camel case:
useSpringBootDevtools=true
And for your build.gradle file, use the following syntax for your conditional dependency:
if(useSpringBootDevtools.toBoolean())
{
// your conditional dependency here
}
Make sure to append toBoolean() to your key since it's not casted automatically by Gradle.

Building a project with Groovy extension methods in it

I'm trying to build a simple Groovy project which contains a package with a Groovy extension method.
When I try to compile the project the classes using the extension method can't find it. The descriptor and the class are picked up correctly by the IDE.
I guess the problem is that the extension method is needed at compile time by which it probably hasn't been compiled yet.
I've tried creating different sourceSets but with no success.
dependencies {
compile 'org.codehaus.groovy:groovy:2.4.7'
compile 'org.membrane-soa:service-proxy-core:4.2.2'
testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
extensionCompile 'org.codehaus.groovy:groovy:2.4.7'
}
sourceSets {
extension {
groovy {
include '**/ClosureExtension.groovy'
}
}
main {
groovy {
compileClasspath += extension.output
}
}
}
The extension method lives in src/main/groovy/com/predic8/membrane/dsl/extension and the rest of the project in src/main/groovy/com/predic8/membrane/dsl/.
P.S.: The project classes are all annotated with #CompileStatic.
One approach: separate the extension code into its own project, and produce a jar from that project. Then, in another project, the DSL code can use that jar and specify the extension jar as a dependency.
This would make a huge answer, so I mocked it up and placed it on GitHub here (with all due credit to mrhaki's post). There are two projects: extension and dsl. Assuming you understand multi-project builds in Gradle, the essence is this line from dsl/build.gradle:
compileGroovy.dependsOn tasks.getByPath(':extension:jar')

How can I make Gradle extensions lazily evaluate properties that are set dynamically by tasks?

I'm pretty new to working with Gradle and I'm trying to develop a plugin that helps manage version numbering. This plugin defines a task that sets the project.version property of the project it's applied to.
What I'm trying to do is make it so that this property is set at the start of every Gradle build. Using Peter's answer to another Gradle question, I've managed to get my task to execute before any other by adding gradle.startParameter.taskNames = [":setProjectVersionNumber"] + gradle.startParameter.taskNames within my plugin's apply method.
However, other plugins (notably 'Maven-publish') rely on the version being specified during the configuration phase:
publishing {
publications {
somePublication(MavenPublication) {
version = project.version
}
}
}
What I'd like to know is if there's a way that I can make the evaluation of properties like version within these extensions as lazy as possible - such that they're not evaluated until a task that depends upon them is called, which in this case might be :publishToMavenLocal.
Below is an SSCCE that demonstrates what I'm hoping to achieve:
// This would be included within the plugin
class SetProjectVersionNumber extends DefaultTask {
#TaskAction
void start() {
// This will set project.version during execution phase
project.version = "1.2.3"
logger.info "Set project version number: $project.version"
}
}
task setProjectVersionNumber(type: SetProjectVersionNumber)
// Imagine this block being replaced by a maven 'publishing' block (or something similar)
ext {
version = project.version
// This will print 'unspecified', as it's evaluated during configuration phase
println "In extension, setting version=$project.version"
}
If you can provide a way to make ext.version equal 1.2.3 in the example above, I believe you've resolved my issue.
If this is asking too much, it may be possible for me to make my plugin generate the version string at configuration-time rather than execution-time. It would be nice to know if I could do it this way, though.
EDIT
In an experimental branch, I tried moving all the version string assignment logic to the configuration-phase (by making it all happen during plugin application rather than during task execution), but I don't believe this will work as the plugin extension has not yet been processed and trying to refer to properties defined in it fail.
EDIT 2
Wrapping the version string assignment logic in a project.afterEvaluate closure seems to have worked:
#Override
public void apply(Project project) {
logger = project.logger
project.extensions.create(EXTENSION_NAME, SemVerPluginExtension)
project.afterEvaluate {
setVersionProjectNumber(project)
addTasks(project)
}
}
In a mock project, I implement build.gradle as follows:
apply plugin: 'semver'
apply plugin: 'maven-publish'
group = 'temp'
buildscript {
repositories {
mavenLocal()
jcenter()
}
dependencies {
classpath 'com.github.tagc:semver-plugin:0.2.2'
}
}
semver {
versionFilePath = 'version.properties'
}
publishing {
publications {
testPublication(MavenPublication) {
version = project.version
assert version
println "Set publication version to $version"
}
}
}
For some reason, this seems to work. Although the version string assignment logic is wrapped in an 'afterEvaluate' closure and the test publication version assignment isn't, the former still occurs before the latter:
Compiling build file '/Users/davidfallah/Documents/semver/TestSemver2/build.gradle' using StatementExtractingScriptTransformer.
Compiling build file '/Users/davidfallah/Documents/semver/TestSemver2/build.gradle' using BuildScriptTransformer.
VERSION FILE PATH=version.properties
Current Git branch: develop
Set project version to 0.2.1-SNAPSHOT
Set publication version to 0.2.1-SNAPSHOT
All projects evaluated.
I'm leaving this question open and unresolved since I'd still like to know if it's possible to do it the way I originally intended. Additionally, I'd appreciate any explanation about why the publication version is assigned after the project version is set, and whether I can depend on that always being the case or whether that's just happening now by accident.
You can use lazy instantiation of GStrings to evaluate properties at run time:
project.tasks.create("example_task", Exec.class, {
commandLine 'echo', "${-> project.someproperty}"
})
Note that you have to use quotation marks and not apostrophes - "${...}" works, but '${...}' does not.

Resources