Skip variable checking in gradle configuration phase - gradle

I have some gradle script where i read some properties file (differen file in different execution configurations) and assign Properties obect to "ext" property in each task.
task provisionMongoDBCopyDockerfile(type: Copy, dependsOn: 'readTestConfiguration') {
from "${projectDir}/deployment/scripts/Dockerfile.mongodb"
into "/tmp/stand/mondodb"
expand(ext.stand)
filteringCharset = 'UTF-8'
}
task readTestConfiguration () {
def props = loadStandProperties('test')
println props
tasks.each {
it.ext.stand = props
println it.ext
}
}
but when i run gradle script i get this error: "Cannot get property 'stand' on extra properties extension as it does not exist" in line with "expand(ext.stand)". How can i solve this problem. I don't want to put all configuration parameters in "gradle.properties" and change it from configuration to configuration.

Consider the following (using Gradle 2.14.1). This effectively sets up a dependency in Configuration phase. Also it uses project.ext versus tasks.ext.
def readTestConfiguration = {
def props = loadStandProperties('test')
println props
project.ext.stand = props
}
def loadStandProperties (def env) {
// use mock data
return ["foo": "bar"]
}
tasks.whenTaskAdded { Task task ->
if (task.name == "provisionMongoDBCopyDockerfile") {
readTestConfiguration()
}
}
task provisionMongoDBCopyDockerfile(type: Copy) {
from "${projectDir}/in"
into "${projectDir}/out"
expand(project.ext.stand)
}

Related

Re-using properties of custom gradle task

I'm defining gradle task like this:
task assembleAppPackage() {
File distDir = file("${projectDir}/dist")
File binDir = file("${distDir}/bin")
File configDir = file("${distDir}/config")
File libDir = file("${distDir}/lib")
doLast {
...using distDir , binDir, etc...
}
}
Somewhere later I want to add some functionality to assembleAppPackage, so I expect something like this to work:
assembleAppPackage {
doLast {
copy {
from "${projectDir}/bin"
into binDir #binDir from original task definition
}
}
}
And gradle claims there is no binDir in scope:
Could not get unknown property 'binDir' for object of type org.gradle.api.internal.file.copy.CopySpecWrapper_Decorated.
How to define task properties which could be later accessed on task extensions? Is it only possible with defining task class?
You can use extra properties for this I think:
task assembleAppPackage() {
ext.distDir = file("${projectDir}/dist")
ext.binDir = file("${distDir}/bin")
ext.configDir = file("${distDir}/config")
ext.libDir = file("${distDir}/lib")
doLast {
...using distDir , binDir, etc...
}
}
(rest of your code unchanged)
On most gradle entities you can use that concept: Set a property using "ext." or
ext {
name1 = value1
name2 = value2
}
See https://docs.gradle.org/current/dsl/org.gradle.api.plugins.ExtraPropertiesExtension.html or google for "gradle extra properties"

refer to Gradle task which is defined later in build

Our build has some generic logic to create tasks from configuration data. There are also several Gradle files on whose execution order I do not want to depend.
Now I need to add a task dependency to a task without knowing if that task will be defined before my part of the build script runs (at configuration time) or after my part.
[Edit: as #canillas writes I can say myTask.dependsOn "otherTask" and "lazily" depend on yet undefined "otherTask", but I need it the other way around.]
Since I can't write tasks["otherTask"].dependsOn myNewTask before "otherTask" is defined, I made the following helper function:
void safelyDoWithTask(String taskName, Closure func) {
def task = tasks.findByName(taskName)
if (task != null) {
func(task)
} else {
project.tasks.whenTaskAdded { task_ ->
if (taskName.equals(task_.getName())) {
func(task_)
}
}
}
}
safelyDoWithTask('otherTask', { it.dependsOn myNewTask })
Now I wonder if there is more canonical way to achieve this?
Consider the following:
// section 1
def dynamicDependencies = [:]
dynamicDependencies['otherTask'] = 'myNewTask'
// section 2
afterEvaluate { project ->
// taskA dependsOn taskB
dynamicDependencies.each { taskA, taskB ->
def task = project.tasks.findByName(taskA)
if (task) { task.dependsOn "${taskB}" }
}
}
// section 3
task myNewTask() {
doLast {
println 'myNewTask !'
}
}
task otherTask() {
doLast {
println 'otherTask !'
}
}
The gist is:
section 1 defines our dependency info in a custom map
section 2 uses the afterEvaluate hook to process the map
because the above is decoupled from the task definitions, we can simply put them in section 3 (or wherever)

Can gradle script property extensions be shared between different scripts

If there is a build.gradle file as follows:
...
apply from: 'Other.gradle'
task hello {
project.ext.hello = "hello"
}
And Other.gradle has:
task getHello {
println project.ext.hello
}
I get an error saying:
Cannot get property 'hello' on extra properties extension as it does not exist
Is there a way to share property extensions between the scripts?
Try setting ext.hello then have the tasks update it
== build.gradle
ext {
hello = null
}
apply from: 'Other.gradle'
task hello {
doLast {
hello = "hello"
}
}
== Other.gradle
task getHello {
doLast {
println hello
}
}
If you really want to be able to set info on a task, you can also use the ext on a task and scope it to a task. If you were implementing a larger plugin you could create an extension and set it on the task.

How to use a parameter in gradle copy task in the destination folder?

Given the following task in gradle, the dev would start a new module by:
gradle initModule -PmoduleName=derp
task initModule(type: Copy) {
description "Initialize an empty module based on the template. Usage: gradle initModule -P moduleName=derp"
onlyIf { project.hasProperty("moduleName") }
from "$rootDir/modules/template"
into "$rootDir/modules/$moduleName"
}
I am unable to run gradle since moduleName is not defined during evaluation, although I was hoping that "onlyIf" would do so.
To solve this I assign it to a locally defined variable in a guard block:
def modName = ""
if (!project.hasProperty("moduleName")) {
logger.error("Invalid moduleName : It can't be")
} else {
modName = moduleName
}
and finally use the new variable to survive the configuration phase.
Is this the right way to do this? It just doesn't feel right.
Additionally if I was using a rule to make this a tad more elegant:
tasks.addRule("Pattern: initModule_<mod name>") { String taskName ->
if (taskName.startsWith("initModule_")) {
def params = taskName.split('_');
task(taskName) {
doLast {
project.ext.moduleName = params.tail().head()
tasks.initModule.execute()
}
}
}
}
The moduleName is not passed around (even if I change it to finalizedBy).
Any help is appreciated.
As you already figured out the property is not available during the configuration phase.
But can postpone the look-up to the execution phase by using
into "$rootDir/modules/" + project.property("moduleName")
instead of
into "$rootDir/modules/$moduleName"

Gradle - publish artifacts

I want to publish artifacts to ivy repository but it doesn't work. I read this article and after read created this sample build:
task ivyPublishTest << {
def buildDir = new File("build")
buildDir.mkdirs()
def fileToPublish = new File("build/file.abc")
fileToPublish.write("asdasdasd")
}
artifacts {
archives(ivyPublishTest.fileToPublish) {
name 'gradle-test-artifact'
builtBy ivyPublishTest
}
}
uploadArchives {
repositories {
ivy {
url "http://my.ivy.repo/ivyrep/shared"
}
}
}
Of course the problem is that it doesn't work. I get this error Could not find property 'fileToPublish' on task ':ivyPublishTest'
In Groovy, def creates a local variable, which is lexically scoped. Therefore, fileToPublish is not visible outside the task action. Additionally, configuration has to be done in the configuration phase (i.e. the declaration and assignment of fileToPublish in your task action would come too late). Here is a correct solution:
task ivyPublishTest {
// configuration (always evaluated)
def buildDir = new File("build")
ext.fileToPublish = new File("build/file.abc")
doLast {
// execution (only evaluated if and when the task executes)
buildDir.mkdirs()
fileToPublish.write("asdasdasd")
}
}
artifacts {
// configuration (always evaluated)
archives(ivyPublishTest.fileToPublish) {
name 'gradle-test-artifact'
builtBy ivyPublishTest
}
}
ext.fileToPublish = ... declares an extra property, a new property attached to an existing object that's visible everywhere the object (task in this case) is visible. You can read more about extra properties here in the Gradle User Guide.

Resources