In the previous chapter, you learned how to define dependencies for your project. Those dependencies are mostly stored somewhere in a repository or a directory structure. A repository usually has a structure to support different versions for the same dependency. Also, some metadata, such as the other dependencies for a module, is saved in the repository.
In our build files, we must define the location of a repository for our dependencies. We can mix different types of repositories, such as Maven and Ivy. We can even use a local filesystem as a repository. We will see how we can define and configure repositories in our build files.
Also, Gradle offers the option of configuring the repository layout, if the repository is using a custom layout. We will learn how to provide credentials for repositories with basic authentication.
If we want to add dependencies from a repository in a Gradle build file, we must explicitly add the repositories
configuration block. Within the configuration block, we define the location of the repository and maybe some extra configuration. In the following example of a build file, we define a Maven repository with a custom location:
// Repositories configuration block, // must be present to define and // configure repositories to get // dependencies in our build script. repositories { // Sample Maven repository with a // custom location. maven { url 'http://mycompany.net/maven' } }
We can include several repositories in our build file. We can even mix the type of repositories, for example to, include both the Ivy repository and a local filesystem. Gradle supports the following types of repositories:
We will see how to use these repositories in our build file later. It is good to realize that Gradle will try to download all artifacts from a dependency, from the same repository that the dependency module descriptor file is found. So, if we have multiple repositories defined in our build script, Gradle will still use the first repository that the module descriptor file is found on to download the artifacts.
Bintray's JCenter is a relatively new public Maven repository, where a lot of Maven open source dependencies are stored. It is a superset of the Maven Central repository and also contains dependency artifacts published directly to JCenter. The URL to access the repository is https://jcenter.bintray.com. Gradle provides a shortcut for JCenter, so we don't have to type the URL ourselves in the repositories
configuration block. The shortcut method is jcenter()
.
In the following example build file, we define a reference to Bintray's JCenter repository using the jcenter()
shortcut:
repositories { // Define Bintray's JCenter // repository, to find // dependencies. jcenter() }
Since Gradle 2.1, the default protocol is https
for the JCenter repository URL. If we want to use the http
protocol, we must set the url
property for the repository. In the next example build file, we will redefine the url
property:
repositories { jcenter { // By default https is used as protocol, // but we can change it with the url // property. url = 'http://jcenter.bintray.com' } }
Optionally, we can assign a name to the repository definition. This can be done for all Maven repositories, and because JCenter is also a Maven repository, we can set the name
property. In the following example build file, we define multiple repositories and set the name
property. We add a new task, repositoriesInfo
, which will display the name
and URL
properties for each repository:
repositories { // Define multiple Maven repositories. jcenter() jcenter { name 'Bintray JCenter legacy' url = 'http://jcenter.bintray.com' } } task repositoriesInfo { description 'Display information about repositories' doFirst { // Access repositories as collection. project.repositories.each { // Display name and URL for each // repository. println "'${it.name}' uses URL ${it.url}" } } }
When we run the
repositoriesInfo
task, we get the following output:
$ gradle -q repositoriesInfo 'BintrayJCenter' uses URL https://jcenter.bintray.com/ 'Bintray JCenter legacy' uses URL http://jcenter.bintray.com
We can configure the central Maven 2 repository in the repositories
configuration block. Gradle provides the shortcut method, mavenCentral
. This configures the central Maven repository with the URL https://repo1.maven.org/maven2/
.
In the next example build file, we will define the central Maven 2 repository for our build:
repositories { // Define central Maven repository // to use for dependencies. mavenCentral() }
Gradle 2.1 uses the https
protocol when we use the mavenCentral
method. If we want to use the http
protocol, we can redefine the url
property and use the http://repo1.maven.org/maven2/
address. In the next example build file, we will redefine the url
property:
repositories { mavenCentral( // Use http protocol for the // central Maven repository. url: 'http://repo1.maven.org/maven2/' ) }
Besides changing the url
property, we can also set an optional name
property when we use the mavenCentral
method. In the following example build script, we assign a value to the name
property. We add a new task, repositoriesInfo
, to display information about the configured repositories:
repositories { // Define multiple Maven repositories. mavenCentral() mavenCentral( name: 'HTTP Maven Central', url: 'http://repo1.maven.org/maven2/' ) } task repositoriesInfo { description 'Display information about repositories' doFirst { // Access repositories as collection. project.repositories.each { // Display name and URL for each // repository. println "'${it.name}' uses URL ${it.url}" } } }
Let's invoke the
repositoriesInfo
task to see the output:
$ gradle -q repositoriesInfo 'MavenRepo' uses URL https://repo1.maven.org/maven2/ 'HTTP Maven Central' uses URL http://repo1.maven.org/maven2/
If we have used Maven on our local computer before there is a great change, we have a local Maven cache with downloaded artifacts. We can use this local cache as a repository in our Gradle build, with the mavenLocal
shortcut method. Although it is possible to use our local Maven cache, it is not advisable because it makes the build dependent on local settings. If we work on a bigger project with more developers, then we cannot rely on the local Maven cache on each developer's computer as the only repository.
In the following example build file, we use the mavenLocal
shortcut method:
repositories { // Define the local Maven cache as // a repository for dependencies. mavenLocal() }
The location of the local Maven cache is determined in the same way as Maven. Gradle will try to find the settings.xml
file in USER_HOME/.m2
or M2_HOME/conf
, where the former takes precedence over the latter. If the settings.xml
file is found, then the location of the local Maven repository defined in the file is used. If settings.xml
cannot be found, or if the local Maven repository location is not defined, then the default location is USER_HOME/.
m2/repository
.
We have learned about shortcut methods to define a Maven repository. If we have our own Maven repository, such as Nexus or Artifactory, we can use the maven
method in the repositories
configuration block. With this method, we can define the url
property to access the repository. We can see this in action in the following example build script:
repositories { // Define a custom Maven repository and // set the url property so Gradle can look // for the dependency module descripts // and artifacts. maven { url = 'http://ourcompany.com/maven' // Alternative syntax is to use // the url method: // url 'http://ourcompany.com/maven' } }
When Gradle finds the module dependency descriptor in the Maven repository, then the artifacts will be searched for in this repository. If the artifacts are stored in another location, we use the artifactUrls
property to specify the location. This way, Gradle will look for the dependency module descriptors in the location specified by the url
property, and for the artifacts in the locations specified by the artifactUrls
property.
The next example build script will define a custom Maven repository, with multiple locations for the artifacts:
repositories { maven { // At this location at the least the // dependency module descriptor files // must be stored. url 'http://ourcompany.com/maven' // Define extra locations where artifacts // can be found and downloaded. artifactUrls 'http://ourcompany.com/jars' artifactUrls 'http://ourcompany.com/lib' // Alternative syntax is to use the // artifactUrls property assignment: // artifactUrls = [ // 'http://ourcompany.com/jars', 'http://ourcompany.com/lib' // ] } }
If we have configured our custom Maven repository with basic authentication, we must provide a username and password to access the repository. In our Gradle build file, we set the username and password in the credentials
block of the maven
configuration. Let's first add the username and password to the build file and later see how we can externalize these properties. The next example build file will use the credentials
configuration block:
repositories { maven { url 'http://ourcompany.com/maven' // Here we assign the username and // password to access the repository. credentials { username = 'developer' password = 'secret' // Alternate syntax is to use // the username and password // methods. // username 'developer' // password 'secret' } } }
It is not a good idea to add the username and password to the build file, because this file is shared with all the developers involved in our project. We fix this using project properties, instead of a hardcoded username and password. The values of the project properties can be set via the command line with the -P
or --project-prop
options. Or, we can add the gradle.properties
file to our project with the names and values of the project properties. The gradle.properties
file must not be put in the version control system of our project, so that the values are private for the developer.
The following example build file uses the mavenUsername
project properties and mavenPassword
for the Maven repository credentials:
repositories { maven { name = 'Company Maven Repository' url 'http://ourcompany.com/maven' // Check that properties mavenUsername // and mavenPassword are set when // we run the script. verifyProperty('mavenUsername') verifyProperty('mavenPassword') credentials { // Use project properties instead // of hard coded username and password. username mavenUsername password mavenPassword } } } /** * Helper method to check if project property * with the given name is set. * * @param propertyName Name of the property to check * @throws GradleException When property is not set. */ void verifyProperty(final String propertyName) { if (!hasProperty(propertyName)) { throw new GradleException("Property $propertyName must be set") } }
When we execute any tasks for this script, we should provide the values for the project properties via the command line:
$ gradle -PmavenUsername=developer -PmavenPassword=secret
Or, we can create the gradle.properties
file in the project directory, with the following contents:
mavenUsername = developer mavenPassword = secret
If we have multiple projects that use the same custom Maven repository, then we can also create a Gradle init script with the correct credentials. A Gradle init script runs before the build starts. In the script, we want to set the credentials for a Maven repository with a specific name. There are several ways to use an init script:
-I
or --init-script
options. Here, we specify the name of the init script.init.gradle
file in the USER_HOME/.gradle
directory. This file is run before every Gradle build on our computer..gradle
extension in the USER_HOME/.gradle/init.d
directory. All Gradle init scripts from this directory are run before every build..gradle
extension in the GRADLE_HOME/init.d
directory. This way, we can package a custom Gradle distribution with init scripts that always need to be executed.Let's take a look at the contents of the init script in the next example init script file:
// Run for all projects. allprojects { // After the project is evaluated, we can access // the repository by name. afterEvaluate { project -> // Check if project contains a repository // with the given name. if (project.repositories.any { it.name == 'Company Maven Repository' }) { // Set credentials for custom Maven repository // with the given name. configure(project.repositories['Company Maven Repository']) { credentials { username 'developer' password 'secret' } } } } }
We must change our project Gradle build file, because the credentials are now set via an init script. We will remove the credentials from the project build file. In the next example build file, we will remove the credentials and helper method, to set the credential properties. The credentials are set by the init script. The following code shows this:
repositories { maven { name = 'Company Maven Repository' url 'http://ourcompany.com/maven' // Credentials are set via init script. } }
Gradle also allows directories to be used as repositories to solve dependencies. We can specify one or more directories using the flatDir
method. Optionally, we can specify a name for the repository. In the next example build file, we specify the lib
and jars
directories to be used as repositories:
repositories { // Define the directories jars and lib // to be used as repositories. flatDir { name 'Local lib directory' dirs "${projectDir}/jars", "${projectDir}/lib" } // Alternate syntax is using a Map // with the flatDir method. // flatDir name: 'Local lib directory', // dirs: ["${projectDir}/jars", "${projectDir}/lib"] }
When we use the flat directory repository, Gradle resolves dependency artifacts based on the artifact name and version. The group part of a dependency is ignored. If we only use flat directory repositories in our project, we can even leave out the group part when we configure the dependencies. Gradle uses the following rules to resolve a dependency:
In the next example build file, we will define a flat directory repository and a single dependency:
repositories { flatDir name: 'Local lib directory', dirs: ["${projectDir}/lib"] } dependencies { traffic group: 'com.traffic', name: 'pedestrian', version: '1.0', classifier: 'jdk16' }
Gradle will resolve the following files in the lib
directory; the first matching file is used:
pedestrian-1.0.jar
pedestrian-1.0-jdk16.jar
pedestr
ian.jar
pedestrian-jdk16.jar
Ivy repositories allow customizable and flexible repository layout patterns. Gradle supports Ivy repositories, and we can configure the repository layout patterns in our Gradle build script. To define an Ivy repository, we use the ivy
method in the repositories
configuration block.
In the following example build file, we define a standard Ivy repository, and we also set the optional name
property for the repository:
repositories { // Define an Ivy repository with // a URL and optional name property. ivy { name 'Ivy Repository' url 'http://ourompany.com/repo' } }
The layout of an Ivy repository defines the patterns used to search module dependency metadata and the dependency artifacts. We can use some predefined layouts in our build scripts. In the previous example build file, we didn't specify a layout. Gradle will then use the default gradle
layout. The next table shows the different layout names we can use, their patterns to find the Ivy metadata XML files, and the artifacts for the dependency:
Name |
Ivy pattern |
Artifact pattern |
---|---|---|
gradle |
|
|
maven |
|
|
ivy |
|
|
The .
in organisation
is replaced with /
.
To use a layout, we use the layout
method inside the ivy
configuration. For example, in the next build script, we use the maven
and ivy
layouts:
repositories { ivy { // Set layout to maven. layout 'maven' name 'Ivy repository Maven layout' url 'http://ourcompany.com/repo1' } ivy { // Set layout to ivy. layout 'ivy' name 'Ivy repository' url 'http://ourcompany.com/repo' } }
To define a custom pattern for the Ivy XML files and the artifacts, we use the pattern
layout. With this layout, we define our own patterns using the tokens defined by Ivy. In the following table, we see the tokens that can be used to build a pattern:
Token |
Description |
---|---|
[organisation] |
This is the organisation name. |
[orgPath] |
This is the organisation name, where |
[module] |
This is the module name. |
[branch] |
This is the branch name. |
[revision] |
This is the revision name. |
[artifact] |
This is the artifact name (or ID). |
[type] |
This is the artifact type. |
[ext] |
This is the artifact file extension. |
[conf] |
This is the configuration name. |
[originalname] |
This is the original artifact name (including the extension). |
To specify an optional token, we enclose the token with parentheses ((
and )
). If the token defined between parentheses is null or empty, then the token is ignored. For example, the [artifact](-[revision]).[ext]
pattern will accept artifact.jar
if revision
is not set and artifact-1.1.jar
if revision
is set.
We define a custom layout in our build script by specifying the layout with the pattern
name, and adding a configuration block where we define the patterns for the Ivy XML files and artifacts. If we don't specify a special pattern for the Ivy XML files, then the artifact pattern is used. We need to define at least one artifact pattern. The patterns are appended to the url
property of the repository. Optionally, we can set the pattern
layout property, m2compatible
. If the value is true
, then the .
in the [organisation]
token is replaced with /
.
In the next example build script, we will define two new repositories with a custom layout:
repositories { ivy { url 'http://ourcompany.com/repo' // Here we define a custom pattern // for the artifacts and Ivy XML files. layout('pattern') { // Define pattern with artifact method. // This pattern is used for both Ivy XML files // and artifacts. artifact '[module]/[type]/[artifact]-[revision].[ext]' } } ivy { url 'http://ourcompany.com/repo1' layout('pattern') { // We can define multiple patterns. // The order of the definitions // defines search path. artifact 'binaries/[organisation]/[module]/[artifact]-[revision].[ext]' artifact 'signed-jars/[organisation]/[module]/[artifact]-[revision].[ext]' // Seperate definition for Ivy XML files // with ivy method. ivy '[organisation]/[module]/metadata/ivy-[revision].xml' } } }
An alternative syntax to define custom patterns is using artifactPattern
and ivyPattern
inside the
ivy
configuration block. We don't have to use the layout
method with this definition. If we don't specify ivyPattern
, then the pattern defined with artifactPattern
is used to find Ivy XML files. In the following example build script, we rewrite the repository definitions from the previous example build file:
repositories { ivy { url 'http://ourcompany.com/repo' // Define pattern with artifact method. // This pattern is used for both Ivy XML files // and artifacts. artifactPattern '[module]/[type]/[artifact]-[revision].[ext]' } ivy { url 'http://ourcompany.com/repo1' // We can define multiple patterns. The order of the definitions // defines search path. artifactPattern 'binaries/[organisation]/[module]/[artifact]-[revision].[ext]' artifactPattern 'signed-jars/[organisation]/[module]/[artifact]-[revision].[ext]' // Seperate definition for Ivy XML files with ivy method. ivyPattern '[organisation]/[module]/metadata/ivy-[revision].xml' } }
To specify the username and password for an Ivy repository with basic authentication, we use the credentials
method, just as we did with the Maven repositories. In the next example build file, we will set the credentials to access an Ivy repository. Take a look at the section about Maven repositories to see how we can externalize the username and password, so that they are not part of the build script code. The following code shows this:
repositories { ivy { url 'http://ourcompany.com/repo' // Here we assign the username and // password to access the repository. credentials { username = 'developer' password = 'secret' // Alternate syntax is to use // the username and password // methods. // username 'developer' // password 'secret' } } }
3.145.103.154