Chapter 2. Working with Repositories

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.

Declaring repositories

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:

Type

Description

Maven JCenter repository

This is a preconfigured repository for Bintray JCenter

Maven central repository

This is a preconfigured repository for Maven Central

Maven local repository

This is a preconfigured repository for the local Maven repository

Maven repository

This is a to-be-configured Maven repository, which has a custom location

Ivy repository

This is a to-be-configured Ivy repository, which has a location and layout

Flat directory repository

This is a local filesystem repository

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.

Using the Maven JCenter repository

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

Using the Maven Central repository

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/

Using the Maven local repository

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.

Using Maven repositories

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:

  • We can use an init script directly from the command line with the -I or --init-script options. Here, we specify the name of the init script.
  • We put the init.gradle file in the USER_HOME/.gradle directory. This file is run before every Gradle build on our computer.
  • We put a file with the.gradle extension in the USER_HOME/.gradle/init.d directory. All Gradle init scripts from this directory are run before every build.
  • We put a file with the .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.
  }
}

Using the flat directory repository

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:

  • [artifact]-[version].[ext]
  • [artifact]-[version]-[classifier].[ext]
  • [artifact].[ext]
  • [artifact]-[classifier].[ext]

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
  • pedestrian.jar
  • pedestrian-jdk16.jar

Using Ivy repositories

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

[organisation]/[module]/[revision]/ivy-[revision].xml

[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier])(.[ext])

maven

[organisation]/[module]/[revision]/ivy-[revision].xml

[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier])(.[ext])

ivy

[organisation]/[module]/[revision]/[type]s/[artifact](.[ext])

[organisation]/[module]/[revision]/[type]s/[artifact](.[ext])

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 . has been replaced by /. This can be used to configure maven2-like repositories.

[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'
    }
  }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.103.154