Getting Gradle 'rootProject' object to honor env vars - gradle

I ran across the following configuration in a Gradle project's buildfile (build.gradle):
codenarcMain {
configFile = rootProject.file("gradle/codenarc/CodeNarcMain.groovy")
}
When I Google "Gradle rootProject" I find this link which makes it look like rootProject is a ProjectDescriptor instance.
But looking at ProjectDescriptor, I don't see any property called file. I see a buildFile and projectDir, but no file property.
Ultimately, I am trying to get Gradle to load the CodeNarc config file from outside the build directory. On my system I have an env var called $CODENARC_HOME with the following directory structure:
CODENARC_HOME/ (say this is /home/myuser/tools/codenarc/)
CodeNarcMain.groovy
CodeNarcTest.groovy
README.md
Now I would like to change the CodeNarc config in Gradle to look something like this:
codenarcMain {
configFile = rootProject.file("CODENARC_HOME/CodeNarcMain.groovy")
}
And then, no matter where CODENARC_HOME is defined, the Gradle build will still be able to locate the config file.
So my questions:
What is the file property on rootProject, and why don't I see it in the API docs (linked above)?; and
How to get rootProject.file(...) to honor system/env vars inside its file path string argument?

rootProject in settings.gradle is-a ProjectDescriptor. rootProject in build.gradle is-a Project. Environment variables and system properties can be accessed in the standard Java way:
codenarcMain {
configFile = rootProject.file("${System.getenv("CODENARC_HOME")}/CodeNarcMain.groovy")
// or: System.getProperty("codenarc.home")
}

Related

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.

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

Compile task is running successful but not generating any class files

I want to implement a gradle build script which compiles some java classes and copy it to to a tomcat directory. I dont want to use Gradle Java plugin since it does many things which are not relevant. I want to define my own compile & deploy tasks which does it. I have implemented it as below -
task compile (type: JavaCompile) {
source = fileTree('$srcdir')
destinationDir = file('$builddir')
classpath = files('lib')
sourceCompatibility = '1.8'
}
task deploy (type: Copy) {
dependsOn compile
from fileTree('build') {
include fileTree('classes')
}
from fileTree('lib') {
include '*'
}
into '${tomcathome}//${projectname}'
}
I have not touched deploy task yet. When i am running compile tasks it is running successful but not generating any class files. I am expecting it to be generated under /build directory.
Please suggest.
Thanks
To summarise the comments in the answer, you need to use GString like #lu.koerfer stated
this way it will always be interpreted as the literal location (a subfolder called $srcdir in this case)
This is needed when using variables inside a string, if don't need to use it in a string then don't (then you don't need a dollar sign).
Not sure how your variables are defined but for build and source directories you should ideally use Gradle provided variables
buildDir to point the build directory
sourceSets.main.java.getSrcDirs() to get source directories (depending on the project structure)
or sourceSets.main.java.srcDirs but note this is going to return the collection of your source directories, depending how you specified your sourceSets, or if you haven't at all then by default is going to return a maven convention structure src/main/java
For some global variables please read about Ext variables

Using a default value between two different build gradle files

I have the following scenario in my Android project:
Project1 --> Build.gradle (1)
Project2--> Build.gradle (2)
Example: Define the following variable:
//first Gradle file
def getProductFlavor() {
//Logic here
Gradle gradle = getGradle()
String requestingTask = gradle.getStartParameter().getTaskRequests().toString()
return requestingTask
}
Instead of defining getCurrentTime() in the second Gradle file,
I call the getCurrentTime() from the first Gradle file.
Maybe my example is wrong and the default value needs to be implementing in another gradle file like the script gradle or somewhere else, but the intent of the example was to clarify what I'm trying to achieve.
The two projects are independents but both belong to the same android project. I want to use ONE def value in both of these gradle files.
I'm a gradle newbie by the way. Never mind if I'm asking this question the wrong way.
Feels like a scenario for external script:
main-project
....| sub-project1
........| src
........| build.gradle
....| sub-project2
........| src
........| build.gradle
....| common.gradle
build.gradle
apply from: '../common.gradle'
def flavor = getProductFlavor()
common.gradle
def getProductFlavor() {
Gradle gradle = getGradle()
String requestingTask = gradle.getStartParameter().getTaskRequests().toString()
return requestingTask
}
ext {
getProductFlavor = this.&getProductFlavor
}

How do I copy a file into my WAR based on profile?

I’m using Gradle 2.7 on Mac Yosemite. I have the following files:
src/main/environment/dev/context.xml
src/main/environment/qa/context.xml
src/main/environment/prod/context.xml
What I would like is if I run a build gradle -Pqa build, the appropriate context.xml file above is copied into my WAR (into the WEB-INF/classes directory is fine). How do I set this up with gradle?
There're many ways of solving the problem. You can configure sourceSets, or include or exclude particular resources when building war file. You can also have single context.xml and perform resource filtering with ReplaceTokens filter.
I've chosen sourceSets:
apply plugin: 'war'
ext.env = project.hasProperty('env') ? project.env : 'dev'
sourceSets {
main {
resources {
srcDir "src/main/environment/$env"
}
}
}
The trick is to include/process only the env being passed. If no env is passed dev will be picked for further processing. Have a look a the demo.
You would have to do that using the environment variable. Have the system properties in a file. Read them in the build.gradle and based on it include the context.xml into the war.

Resources