I am using Gradle in my project. I have a task for doing some extra configuration with my war. I need to build a string to use in my task like, lets say I have:
task extraStuff{
doStuff 'org.springframework:spring-web:3.0.6.RELEASE#war'
}
This works fine. What I need to do is define version (actually already defined in properties file) and use this in the task like:
springVersion=3.0.6.RELEASE
task extraStuff{
doStuff 'org.springframework:spring-web:${springVersion}#war'
}
My problem is spring version is not recognised as variable. So how can I pass it inside the string?
If you're developing an Android application using Gradle, you can declare a variable (i.e holding a dependency version) thanks to the keyword def like below:
def version = '1.2'
dependencies {
compile "groupId:artifactId:${version}"
}
I think the problem may lay on string literal delimiters:
The string literals are defined exactly as in groovy so enclose it in single or double quotes (e.g. "3.0.6.RELEASE");
Gstrings are not parsed in single quotes strings (both single '...' or triple '''...''' ones) if i recall correctly;
So the code will be:
springVersion = '3.0.6.RELEASE' //or with double quotes "..."
task extraStuff{
doStuff "org.springframework:spring-web:${springVersion}#war"
}
On android there are actually 2 possibilities how to achieve this. It really depends which suits your needs. Those two possibilities have their pros and cons. You can use def variable or ext{} block. Variable def is awesome because it lets you click on the variable and points exactly where it is defined in the file compared to ext{} block which does NOT points to that exact variable. On the other hand ext{} has one good advantage and that is you can refer variables from project_name/build.gradle to project_name/app/build.gradle which in some cases is very useful BUT as I said if you click on that variable lets say only inside only one file it wont points out to the definition of that variable which is very bad because it takes you more search time if your dependency list grows.
1) def option which is propably best and saves you search time.
def lifecycle = '2.0.0'
dependencies {
implementation 'androidx.lifecycle:lifecycle-extensions:$lifecycle'
}
2) second ext{} block. Its kinda ok if dependency list is not huge.
ext {
lifecycle = '1.1.1'
}
dependencies {
implementation 'androidx.lifecycle:lifecycle-extensions:$lifecycle'
}
3) In some cases if you want to share variables between project_name/build.gradle and project_name/app/build.gradle use ext{}
in project_name/build.gradle you define kotlin_shared_variable:
buildscript {
ext.kotlin_shared_variable = '1.3.41'
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_shared_variable"
}
}
which you can use in project_name/app/build.gradle
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_shared_variable"
}
and of course you can combine them.
see here.
Double-quoted strings are plain java.lang.String if there’s no interpolated expression, but are groovy.lang.GString instances if interpolation is present.
Gradle uses Groovy as a DSL. Here "${springVersion}" is a placeholder, what you want is to interpolate, so you should use the double quote, only the double quote in GString has the capability to interpolate.
You can also define variables in the gradle.properties file at the root of your project. You don't have to use double quotes in that file. You would need to add the following line:
lifecycle=2.0.0
Related
Sorry if it was not clear enough.
I have the following groovy snippet (from Jenkins)
def jdk = jobConfig.java
jobConfig.env.JAVA_HOME="${tool '$jdk'}"
jobConfig.env.PATH="${env.JAVA_HOME}/bin:${env.PATH}"
How can I substitute the value of $jdk variable inside the single quotes on this line?
jobConfig.env.JAVA_HOME="${tool '$jdk'}"
For example, this works with no problems. The usage of tools is OK:
jobConfig.env.JAVA_HOME="${tool 'openjdk_11.0.14'}"
But I want to set the hardcoded value of 'openjdk_11.0.14' to the value coming from def jdk = jobConfig.java
I tried a few variations but couldn't find the solution.
Many thanks
How can I reference the $jdk variable inside the single quotes?
It isn't clear what you mean by that but what you have is this:
jobConfig.env.JAVA_HOME="${tool '$jdk'}"
There are a few things wrong with that but to address how to deal with the single quotes, 1 of the issues is you have nested $ which is going to confuse the situation.
if you are trying to surround the value of jdk with single quotes, you can do this:
def someJavaHomeRelatedVariable ="'${jdk}'"
Note that the quotes are outside of the {} expression.
A separate issue is your use of tool in that expression, but the above explains how to deal with surrounding the value of jdk with single quotes.
EDIT
The question isn't clear but maybe you are wanting to do something like this:
def sout = new StringBuilder()
def jdk = jobConfig.java
def proc = ['tool', jdk].execute()
proc.consumeProcessOutput(sout, null)
proc.waitForOrKill(2000)
jobConfig.env.JAVA_HOME = sout.toString()
In an Android Studio (and presumably ANY) gradle file, the following code works:
task build {
}
And one minor change causes a complete meltdown:
task build
{
}
This has come up in other threads before, but in the context of fixing the build files. My question is why can't gradle/groovy be made to deal with either bracing style? Many other languages cope just fine with it, so what's the big deal here?
It's actually all right there in the error message:
build file '.../build.gradle': 80: Ambiguous expression could be a parameterless closure expression, an isolated open code block, or it may continue a previous statement;
solution: Add an explicit parameter list, e.g. {it -> ...}, or force it to be treated as an open block by giving it a label, e.g. L:{...}, and also either remove the previous newline, or add an explicit semicolon ';' # line 80, column 1.
Because of a Groovy syntax sugar to make methods with a lambda as the last parameter look line language constructs, the following code blocks:
task build {}
task build2(type: Copy) {}
are equal to their more regular form:
task build({})
task build(type: Copy, {})
Now, you do not really want those curly braces there to delimit a regular code block, but a Groovy lambda, which should be passed as a parameter to the build method.
Yet from the looks of it, Groovy can't really decide if it really is a lambda being passed as a parameter to the method in the previous line or an unrelated code block when you put a newline in between. And there you go, an ambiguousness as described in the error message, right there.
Following the advice in the error message, you can also use the following syntax instead of the one where you are escaping the new-line character:
task build
{ ->
}
Finally, the task keyword used to invoke the dynamic method (named build in your example) is not Groovy specific, but a Gradle DSL feature.
In case anyone reading this is wondering, the work-around is simple enough.
task build \
{
}
I was just wondering as to the "why"...
I have inherited a cookbook that sets some attributes in the ./attributes/default.rb file as per normal.
However, we have a problem with one of the lines is, which is:
default["obscured"]["mysql"] = "#{node['jboss']['jboss_home']}/modules/com/mysql/jdbc/main"
When run, it write this into the node as:
{}/com/mysql/jdbc/main
I can confirm that the node['jboss']['jboss_home'] attribute exists and has correct values.
So, I cannot see any problem with the above, except that every other declaration of this type in our cookbooks has single quotes on the attribute to be set (i.e. left side), not double quotes. I haven't heard this of as being an issue before, but I am pretty new to chef.
Is there any rule that says they must be single quotes?
The answer is that there is no rule.
Using double-quotes in something like this is completely fine:
default["obscured"]["mysql"] = blah blah
The reason I know that is that I just found one being set, with double quotes, that actually works. :-)
What you have there is fine, how are you confirming the value of node['jboss']['jboss_home'] and how are you using it in the template?
In Ruby single and double quoted literals both become Strings but single quotes are relatively literal while double quotes allow backslash escapes and #{} interpolation.
You are most likely hitting the derived attributes problem:
https://coderanger.net/derived-attributes/
The attribute code in your cookbook is getting parsed before the jboss_home attribute is being set. One way or another the solution is to move the interpolation into recipe code.
You could just use a plain old ruby variable instead of the attribute you are trying to construct -- particularly if nothing else in your system ever sets that attribute.
You also should be able to delete the declaration from your attributes file and use this in recipe code as well:
node.default_unless["obscured"]["mysql"] =
"#{node['jboss']['jboss_home']}/modules/com/mysql/jdbc/main"
Although you need to place that statement early in your run_list, before you ever use node["obscured"]["mysql"] as an argument to any resource.
I have recently upgraded to Susy2 and having to rework my base templates with new susy-breakpoints instead of at-breakpoint.
With the new susy-breakpoint I need to define a breakpoint and a layout for the short hand like so "60em, 12" and I have tried storing this in a variable e.g. "$large" so that I can pass it into various classes.
However as it is a single variable the mixin only sees it as one value so I can only store one value. Is there a way two store both values in a variable?
Yep. Sass has Variable Arguments which are great for handling this situation:
#include susy-breakpoint($large...) {
// Your code here
}
The ... does the magic.
For DSL purposes I want to detect methods defined like:
def "methodName"() {}
or
def "This is another method name"() {}
Is there any way to do that using reflection?
This information is not available at runtime. Even with an AST transformation, you would not be able to figure out that the method was defined using a string.
For this, you would have to write your own AntlrParserPlugin and use it using a custom CompilerConfiguration. Then in methodDef from AntlrParserPlugin, when the name of the method is parsed, you could check that the character before the name is a double quote. If a double quote is found, then add a custom annotation to the generated MethodNode, so that the information is available at runtime...