Understanding the dependency cache

The dependency cache of Gradle tries to minimize the number of remote requests and downloads so that builds can be fast and reliable. The cache has two parts to perform proper dependency caching:

  • First, it has a cache for dependency metadata (POM or Ivy descriptor files) for a dependency group, name, and version. Gradle keeps a separate cache for each repository. So, if the same dependency is found in multiple repositories, then the metadata information is cached in multiple dependency metadata caches.
  • The dependency cache also has a single cache with downloaded artifacts for the dependencies. The multiple metadata caches share the same cache for downloaded artifacts. The artifacts are stored by the SHA1 hash code of their contents and not by metadata, such as group, name, or version.

The separation of a metadata cache based on the repository and the artifact cache provides enough flexibility to perform repeatable and reliable dependency resolution. If the dependency metadata cannot be resolved by Gradle, then the dependency resolution will stop, even if the local cache has a copy of the artifact that was downloaded from a different repository (not defined in our build). This repository independence isolates builds from each other and prevents problems with dependency artifacts.

Gradle first tries to determine the SHA1 checksum for an artifact file before downloading the artifact. If the checksum can be determined, the file will not be downloaded if it is already in the cache with the same checksum. Gradle also tries to reuse artifacts from the local Maven repository. If the checksum for an artifact in the local Maven repository matches the checksum for the artifact from the remote repository, then the artifact doesn't need to be downloaded and can be copied from the local Maven repository.

Because Gradle uses an SHA1 checksum for the artifact contents, different versions for the same artifact can be stored. For example, when an artifact is part of a changing module or the contents of the artifact have changed in the repository without a change in the version number.

Both the metadata cache and artifact cache are stored in the directory defined by the GRADLE_USER_HOME environment variable that is, by default, the .gradle/caches directory in the user home directory. Gradle uses a sophisticated locking mechanism for the caches, so multiple projects can use the cache directories and files simultaneously. In the next example build file, we create the artifactsLocation task to print out where the downloaded artifacts are stored:

apply plugin: 'java'

repositories.jcenter()

dependencies {
  compile 'org.slf4j:slf4j-api:1.7.7'
  runtime 'ch.qos.logback:logback-classic:1.1.2'
}

task artifactsLocation {
  description 'Show location of artifact on disk'

  doFirst {
    configurations.runtime.each { println it }
  }
}

When we execute the artifactsLocation task, we see in the output that the files are stored in the .gradle/caches directory in the user home directory (/Users/mrhaki). We also see the SHA1 checksums with which the directory names are used. The following code shows this:

$ gradle -q artifactsLocation
/Users/mrhaki/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.7/2b8019b6249bb05d81d3a3094e468753e2b21311/slf4j-api-1.7.7.jar
/Users/mrhaki/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-classic/1.1.2/b316e9737eea25e9ddd6d88eaeee76878045c6b2/logback-classic-1.1.2.jar
/Users/mrhaki/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-core/1.1.2/2d23694879c2c12f125dac5076bdfd5d771cc4cb/logback-core-1.1.2.jar

Command-line options for caching

We can use the --offline command-line option to skip any network requests. So, with this option, Gradle never tries to access remote repositories and all information is fetched from the Gradle dependency caches. If the information in the caches is not sufficient for a build, then the build fails.

With the --refresh-dependencies option, we can refresh the metadata caches. If, for some reason, we expect the metadata to be no longer correct, we can use this option. Gradle will then refresh all information in the metadata caches for each repository. Artifacts are only downloaded when the SHA1 checksum is different than the checksum for artifacts in the artifacts cache.

Changing cache expiration

A dependency with a static version can be easily cached. The contents of the artifact has a checksum, and this can be used to either use the cache or download the artifact (and place it in the artifact cache). A dependency with a dynamic version or changing module can have a changing artifact, so we need to be able to customize the cache settings. We can change the expiration time for cached dependencies with a dynamic version and changing modules. The default expiration time is 24 hours. After the expiration time, Gradle will invalidate the cache and determine whether an artifact needs to be downloaded again.

We change the expiration time for dependencies with a dynamic version using the cacheDynamicVersionsFor method of the resolutionStrategy configuration closure. The method accepts a number and time unit to set the value for the cache expiration. The time unit can be either of the java.util.concurrent.TimeUnit type or a string that is converted to TimeUnit.

To change modules, we use the cacheChangingModulesFor method to change the expiration time. This method also accepts a number and time unit just as the cacheDynamicVersionsFor method does.

In the next example build file, we change the cache expiration for both dynamic versions and changing modules for runtime configurations. We can also set it for all configurations with the all method and configuration block. The following code shows this:

// Import needed for cache methods time unit.
import java.util.concurrent.TimeUnit

apply plugin: 'java'

repositories.jcenter()

configurations {
  runtime {
    resolutionStrategy {
      // Change expiration time for caching
      // dynamic version to 30 minutes.
      cacheDynamicVersionsFor 30, 'minutes'

      // Alternative syntax is using TimeUnit:
      // cacheDynamicVersionsFor 1, TimeUnit.HOURS

      // Change expiration time for cached
      // changing modules to 5 minutes using
      // java.util.concurrent.TimeUnit.
      cacheChangingModulesFor 5, TimeUnit.MINUTES

      // Or we could use string notation.
      // cacheChangingModulesFor 1, 'minutes'
    }
  }

  // Alternatively we could apply
  // this to all configurations:
  // all {
  //     resolutionStrategy {
  //         cacheDynamicVersionsFor 4, 'hours'
  //         cacheChangingModulesFor 10, 'minutes'
  //     }
  // }
}

dependencies {
  compile 'org.slf4j:slf4j-api:1.7.7'

  runtime 'ch.qos.logback:logback-classic:1.1.2'
}

Gradle knows about artifacts that are stored in a Maven repository, and that if the version attribute ends with -SNAPSHOT, the module is a changing module. We can also define in our build script whether a dependency is a changing module, for example, if this cannot be derived from the version attribute. We must set the changing property to the value true in the configuration closure for a dependency.

In the following example build file, we have the com.vehicles:cars dependency, which is a changing module, but we use the static version 1.0:

apply plugin: 'java'

repositories {
  maven {
    url 'http://ourcompany.com/maven'
  }
}

dependencies {
  compile('com.vehicles:cars:1.0') {
    // Instruct Gradle this a changing
    // module, although it cannot
    // be derived from the version attribute.
    changing = true
  }

  // Other syntax using the map notation:
  // compile group: 'com.vehicles', name: 'cars',
  //         version: '1.0', changing: true
}
..................Content has been hidden....................

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