Gradle Dependencies and Dependency Configurations TODEPLETE: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
Line 43: Line 43:
=Declaring Dependencies=
=Declaring Dependencies=


Dependencies for a project are declared in the associated [[Gradle_Project_and_Build_Script#dependencies.7B.7D|build.gradle]] using the dedicated [[Gradle_Project_and_Build_Script#dependencies.7B.7D|dependencies{...}]] script block. The [https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:dependencies(groovy.lang.Closure) dependencies()] method executes the given closure against the [[#Configuration_Container|configuration container]] of this project, which is passed as the object delegate to the closure. The script block lists [[Gradle_Concepts_ToDeplete#Dependency_Configuration|dependency configurations]] known to the project, followed by list of dependencies.
Dependencies for a project are declared in the associated [[Gradle_Project_and_Build_Script#dependencies.7B.7D|build.gradle]] using the dedicated [[Gradle_Project_and_Build_Script#dependencies.7B.7D|dependencies{...}]] script block. The [https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:dependencies(groovy.lang.Closure) dependencies()] method executes the given closure against the [[#Configuration_Container|configuration container]] of this project, which is passed as the object delegate to the closure. The script block lists [[#Dependency_Configuration|dependency configurations]] known to the project, followed by list of dependencies.


<syntaxhighlight lang='groovy'>
<syntaxhighlight lang='groovy'>

Revision as of 20:28, 19 May 2018

External

Internal

Overview

A dependency is an artifact, usually located in a repository, the project needs. From a very generic perspective, a dependency can be thought of as a pointer to another piece of software.

Gradle groups dependencies in, and handles them as sets, referred to as dependency configurations. A dependency configuration is a named set of dependencies and artifacts, grouped together for a specific goal. For example, some dependencies should be used during the compilation phase, whereas others need to be available during the testing phase, or at runtime. The concept is somewhat similar to the Maven dependency scope. Internally, a dependency configuration is implemented as a Configuration instance. Each configuration is identified by a unique name. Many Gradle plugins add pre-defined configurations to the project. For example, the Java plugin adds configurations to represent the various classpaths needed for compilation, testing, etc. A dependency configuration has three main purposes:

  • To declare dependencies: plugins use dependency configurations to allow build authors to declare what other sub-project of external artifacts are needed during the execution of tasks defined by the plugin.
  • To resolve dependencies: plugins use dependency configurations to find and download the dependencies that are needed during the build
  • To expose artifacts for consumption: plugins use dependency configurations to define what artifacts it generates. Configurations are using during the artifact publishing process.

Additionally to the dependency configurations introduced by plugins, custom configuration may be defined. A configuration can extend other configurations to form an configuration hierarchy. Child configurations inherit the whole set of dependencies declared for any of its parent configurations.

Configuration Container

https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.ConfigurationContainer.html

All dependency configurations associated with a project are maintained within a configuration container, which allows declaring and managing configurations. The configuration container is one of the project's containers. Dependency configuration is perform by declaring dependency details in the build.gradle dependencies{...} script block, which applies the configuration closure on the delegate configuration container instance.

Dependency and Dependency Configuration Info

The dependencies of a project and their association with various dependency configurations can be displayed with:

gradle dependencies 

The dependency configuration can also be displayed by accessing the configuration container of the project:

task displayconfigs {
    doFirst {
        println "project dependency configurations: "
        configurations.each { println '  ' + it.name }
    }
}

Declaring Dependencies

Dependencies for a project are declared in the associated build.gradle using the dedicated dependencies{...} script block. The dependencies() method executes the given closure against the configuration container of this project, which is passed as the object delegate to the closure. The script block lists dependency configurations known to the project, followed by list of dependencies.

dependencies {
    implementation 'org.slf4j:slf4j-api:1.7.12'
    api 'com.google.guava:guava:23.0'
    ...
}

Note that the declared dependencies must be available in a declared repository, so repositories must be declared.

Dependencies can also be declared without a version, and dependency constraints can be used to manage the version, including the transitive versions.

dependencies {
    implementation 'org.slf4j:slf4j-api'
    constraints {
        implementation 'org.slf4j:slf4j-api:1.7.12'
    }
}

When declaring a dependency, a reason for the declaration can be provided in-line:

dependencies {
    implementation('org.slf4j:slf4j-api:1.7.12') {
        because 'because we like SLF4J'
    }
}

Dependencies between Subprojects

Dependencies between the subprojects of the same root project must be explicitly declared. If classes belonging to "subproject-B" depend on classes in "subproject-A", then in the build.gradle of subproject-B we must add:

dependencies {
    ...
    implementation project(':subproject-A')
    ...
}


At runtime, Gradle will attempt to locate declared dependencies needed for the task being executed. This process may involve access and download from a remote repository, retrieval from a local directory, or building another project, in case of a multi-project build. This process is called dependency resolution https://docs.gradle.org/current/userguide/introduction_dependency_management.html#sec:dependency_resolution. A specific dependency may find itself in the dependency graph because it was declared in the build script or it is dependency of a declared dependency (transitive dependency).

Whenever Gradle tries to resolve a dependency in a repository, it looks for a metadata file and the default artifact file, a JAR. The build fails if none of these artifact files can be resolved. Under certain conditions, tweaking the way Gradle resolves artifacts for a dependency might be desired. TODO https://docs.gradle.org/current/userguide/declaring_dependencies.html#sub:resolve_specific_artifacts_from_dependency

Once a dependency is resolved, Gradle stores into a local cache, referred to as the dependency cache.

Dependencies are declared with:

dependencies { 
 ... 
}

in:

build.gradle

Configuration, in this context, does not refer to a configuration file, as in a settings configuration or a build configuration. It refers to named set of dependencies or artifacts, and it can probably thought of as being a concept similar to a Maven scope.

TO Deplete

Dependency Management

Dependency management is a technique for declaring, resolving and using dependencies required by the project in an automated fashion.

Dependency Types

Module Dependency

Module dependency is the most common form of dependency. It refers to a module in a repository.

TODO https://docs.gradle.org/current/userguide/dependency_types.html#sub:module_dependencies

Local File Dependency

TODO:

Project Dependency

TODO:

Gradle Distribution-Specific Dependency

TODO https://docs.gradle.org/current/userguide/dependency_types.html#sub:api_dependencies

Dependency Constraint

A dependency constraint defines requirements that need to be met by a module to make it a valid result for a dependency resolution process. A recommended practice for large projects is to declare dependencies without versions and use dependency constraints for version declaration. The advantage is that dependency constrains allow you to manage versions of all dependencies, including transitive ones, in one place.

Dynamic Version

An aggressive approach for consuming dependencies is to declare that a module depends on the latest version of a dependency, or the latest version of a version range. This approach is called dynamic versioning. By default, Gradle caches dynamic versions of dependencies for 24 hours. Within this time frame, Gradle does not try to resolve newer versions from the declared repositories. This threshold can be configured. The build.gradle syntax for dynamic versioning is:

dependencies {
    implementation 'org.slf4j:slf4j-api:1.2.+'
}

Changing Versions or Snapshots

In Maven, changing versions are referred to as napshots.

TODO when needed https://docs.gradle.org/current/userguide/declaring_dependencies.html#sub:declaring_dependency_with_changing_version

Resolution Rule

A resolution rule influences the behavior of how a dependency is resolved. Resolution rules are defined as part of the build logic. TODO https://docs.gradle.org/current/userguide/customizing_dependency_resolution_behavior.html.

Transitive Dependency

A transitive dependency is a dependency of a dependency of a module. The immediate dependencies are declared in a module's metadata, and the build system is supposed to automatically resolve the dependency graph. TODO: https://docs.gradle.org/current/userguide/managing_transitive_dependencies.html. Gradle offers facilities to inspect the transitive dependency graph.

The Dependency Cache

https://docs.gradle.org/current/userguide/dependency_cache.html

Once a dependency is resolved as result of the dependency resolution, Gradle stores the associated artifacts in a local cache, known as the dependency cache.

The Gradle dependency cache consists of two storage types located under Gradle user home caches subdirectory: file-based storage for downloaded artifacts and raw metadata files, and a binary store of resolved module meta-data.

Example:

$HOME/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.12/8e20852d05222dc286bf1c71d78d0531e177c317/slf4j-api-1.7.12.jar