How can I add properties in Gradle which are similar to Maven's properties?
The use case is this: I want to have a file which declares all versions for repo dependencies so they are unified in a single place for a multi module project
compile group: 'javax.servlet.jsp.jstl', name: 'jstl', version: '1.2'
In Maven you can have properties like this:
<properties>
<jstlVersion>1.2</jstlVersion>
</properties>
Is it ok to use Gradle's external properties? Or just add them to the gradle.properties file?
Project properties defined in the root build file are available to subprojects. So if you have this in your root build.gradle file:
ext.commonsLangVersion = "2.4"
then you can use that in the dependencies {} block of a subproject like so:
dependencies {
implementation "commons-lang:commons-lang:${commonsLangVersion}"
}
You can also define such properties in the root gradle.properties file instead of the root build file. You use them in the same way.
If you really feel the need to put the versions in a separate file, you can do so. Simply add the following line to the root build file:
apply from: "dependencies.gradle"
Within the dependencies.gradle file, you can define the extra project properties as if they were in the root build file directly:
ext.commonsLangVersion = "2.4"
Note Normally, the values set in the build script take precedence over the values in gradle.properties. But if you set a value in the root build script as above, then any matching value in gradle.properties will override it in subprojects.
This behaviour is somewhat confusing and unique. For behaviour that is consistent with Gradle single-project builds you would need to use the following in the root build script:
allprojects {
apply from: "dependencies.gradle"
}
As a general rule of thumb, any given property should be declared/defined in either the build script or gradle.properties. If users want to override a particular property value, they can do so in $USER_HOME/.gradle/gradle.properties.
[EDIT I have updated the above note to clarify the actual behaviour]
One final thing: Gradle also allows you to control the versions of transitive dependencies via dependency constraints. You can also import Maven BOMs if you're using Gradle 4.6 or newer.
Found this as a possible solution, though I don't really like that uses relative path to the properties file.
Point 7 from here:
https://proandroiddev.com/make-your-build-gradle-great-again-c84cc172a654#8029
Related
I am writing a custom annotation processor in Java which needs to create a file.
It seems to me the best location for that file would be in a new folder inside the Gradle's $buildDir.
For a project without modules, the environment property "user.dir" seems to hold a value I could use.
However, that environment property changes if the project has modules and the gradlew build command is executed either from inside or outside a module.
What is the best approach to actually get in Java the Gradle build directory of the module in which the annotation processor is declared ?
P.S.
I do not want to create that file in the "build/generated" folder (this is what processingEnv.getFiler().createSourceFile(..) does).
You should do it the other way around : choose a location and set it up in your build.gradle
tasks.withType(JavaCompile) {
options.annotationProcessorGeneratedSourcesDirectory = file("your/custom/path")
}
I got some source code and was asked to build it. It was a Gradle project. So I changed to the project directory and ran:
$ gradle clean assemble
and the following error came up:
...
* What went wrong:
A problem occurred evaluating root project 'pcase'.
> Could not get unknown property 'postgresql.jdbc' for root project 'pcase' of type org.gradle.api.Project.
...
There is a settings.gradle file in the project folder too. It contains:
rootProject.name = 'pcase'
I took a look at build.gradle and found lots of occurrences like
${project['x']}
For example:
buildscript {
dependencies {
...
// FlywayDB, JOOQ.
classpath "org.postgresql:postgresql:${project['postgresql.jdbc']}"
classpath "org.flywaydb:flyway-gradle-plugin:${project['flywaydb.plugin.version']}"
classpath "nu.studer:gradle-jooq-plugin:${project['jooq.plugin.version']}"
...
What could be ${project['x']}? Looks like associative array in bash and the build script tries to get the value of the key 'x'.
But I didn't find the place in code where this array would be declared and initialized.
The question is: Is the project buildable or is it better to consult the company that worked at it before me?
From the information provided, the project is perfectly buildable, to some certain extend. First of all, project['a.b.c'] is Groovy syntax to access properties from the project object. They're referred to as project properties.
They can be set via
Project properties via command line: gradle -Ppostgresql.jdbc=x.y.z
System properties via command line: gradle -Dorg.gradle.project.postgresql.jdbc=x.y.z
System properties via gradle.properties: org.gradle.project.postgresql.jdbc=x.y.z
All 3 properties (postgresql.jdbc, flywaydb.plugin.version, jooq.plugin.version) denote the version numbers of the particular build script dependencies. However, which versions to use best is beyond my knowledge. I would certainly consult the respective project websites, Maven artifact search or simply ask the company.
org.postgresql:postgresql is the database JDBC driver and certainly depends on the database version.
org.flywaydb:flyway-gradle-plugin is for database migrations. Try with the latest version.
I wasn't able to find gradle-jooq-plugin on Maven central. It's most likely available on the Gradle Plugin Portal.
I'm fairly new to Gradle, and am enamored by its task-driven approach and customizability. So I have a question that hopefully helps me understand how to do something beyond the basics.
Suppose I have a simple text file that contains information about a project's dependencies. For example, something like
- dependency1
from: 'foobar'
version: '1'
- dependency2
from: 'foobaz'
version: '1'
Note that these are not I have some code that would, from this file, generate a file along the lines as follows:
compile 'commons-lang:commons-lang 2.6'
testCompile 'org.spockframework:spock-core:1.1-groovy-2.4'
Is there a way to configure my project so that my project's dependencies are taken from this file (not exclusively)?
Do note that the text file is also used to generate other artifacts that are used by other tasks (for example, a file to be added to a Docker container), so while it may be possible to, say, declare the dependencies normally and generate the text file instead, it is not a trivial process to do so at this time.
Yes, you can write your own groovy function that parses the file and creates a List. Then you can pass this map to the dependencies closures:
List<String> compileLibraries() {
// ... parse yaml and return list
}
dependencies {
compile compileLibraries()
}
Also, to use a yaml-parsing library, consider setting up a custom gradle subproject in the special buildSrc subfolder and writing your helper function there.
See this old post for more details: https://discuss.gradle.org/t/programmatically-adding-dependencies/7575/12
And here for buildSrc projects:
https://docs.gradle.org/current/userguide/organizing_build_logic.html#sec:build_sources
I realize there are a lot of posts online regarding Gradle setup. That being said, I have researched heavily and not found exactly what I'm looking for, or I'm using incorrect terms to do so. I'm using Gradle version 3.3.
So I've got multiple Gradle projects, each of which is maintained separately. There is no master Gradle project. Each projects has its own modules, build, and settings file. The structure of this is as so:
Projects
A
a1
build.gradle
a2
build.gradle
build.gradle
settings.gradle
B
b1
build.gradle
b2
build.gradle
build.gradle
settings.gradle
What I'm attempting to do is make B dependent on A's modules. Let's assume one of the modules in B is dependent on a1. In B's settings, I've done the following:
rootProject.name = 'B'
rootProject.setProjectDir(new File(".")
include 'a1'
project(':a1').setProjectDir(new File(settingsDir.getParentFile(), "/A/a1"))
The way I'm storing version numbers is through each project's build.gradle file in the ext closure. I then access them through the project. Here's how B's build file looks:
ext {
freemarkerVersion = '2.3.19'
}
dependencies {
compile project(':a1')
compile group: 'org.freemarker', name: 'freemarker', version: rootProject.properties.get('freemarkerVersion')
}
What I'm seeing is B is able to resolve its dependencies and is attempting to compile project a1, but it is using B's version numbers instead of A's. I verified this by putting a common dependency in both projects with different version numbers. The dependency showed up using B's version. I also changed the version number in B and further confirmed this. So if I could get any help for using project-appropriate versions in each of their own build.gradle files, that would be great!
EDIT: Updated post, figured out previous problem was from relative path not resolving.
Not to toot my own horn or anything, but I'm posting the solution I came up with, as I had no other answers knocking down my door.
The first thing I did was moved all of my version properties to an external gradle.properties file, instead of in an ext closure in the project's build.gradle file. Doing this, the project will load the properties file by default when compiled from its own context. It will of course be overridden from the user.home gradle.properties file, so keep this in mind. Example gradle.properties:
a_freemarkerVersion = 2.3.19
When using one project's modules from another project, you'll need a way to separately link the two so Gradle can resolve the dependency's properties. I achieved this by defining a method to load in the desired project's properties file. This method looks like so:
def addConfig(String parent, String filename) {
Properties props = new Properties()
props.load(new FileInputStream(new File(project.projectDir.getParent(), "/${parent}/${filename}")))
props.each { prop ->
project.ext.set(prop.key, prop.value)
}
}
addConfig("A", "gradle.properties")
All this method does is goes up one directory, goes into the project specified, and retrieves its gradle.properties file and loads these variables into the current project's properties. With that being said, there's one thing to note here: if you define the same variable in both, one of them will be overridden. To avoid this, I just prefixed all variables with the project name and then an underscore. This will guarantee they'll never conflict with one another.
I accessed the variables in all projects with this syntax:
dependencies {
compile group: 'org.freemarker', name: 'freemarker', version: "${a_freemarkerVersion}"
}
The rest of the setup is the same as I defined in my initial post. Just make sure to include the dependent module, specify its project directory, and compile that project from within the project's dependencies.
I have a several projects in a flat structure with dependencies between them.
Currently in each one a have a definition similar to this defining the versions used within the build script:
ext {
versions = [
scala: '2.11.1',
scalatra: '2.3.0',
jetty: '9.1.5.v20140505',
scalaTest: '2.3.0',
junit: '4.8.1',
]
}
and later usage:
compile group:'org.scala-lang' , name:'scala-library',version: versions.scala
As I have this defined in each build.gradle what I would rather want is to define the versions in one place and read in all files in the current build.
Writing to a global value will not be sufficient here as the combination of build files involved in a build may change (e.g. when testing a specific component only none of the components depending on it will be defined)
Put this map into its own .gradle file and include into your projects with apply from: '../dependencies.gradle'. Similar to what Gradle has in its own codebase