1Dependencies 2============ 3 4Each gradle project can have multiple (named) "configurations" 5and each configuration can have dependencies attached to it. 6 7There are some standard conventions so, for example, the Java plugin 8adds standard configurations such as "api", "implementation", 9"testImplementation" and others. These configurations can also inherit 10from each other; more about this typic can be found here: 11 12https://docs.gradle.org/current/userguide/dependency_management_for_java_projects.html#dependency_management_for_java_projects 13https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation 14https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_plugin_and_dependency_management 15 16Lucene typically uses three configurations and attach project 17dependencies to them: 18 19api - makes a dependency available for main classes, tests and any 20 other modules importing the project (exportable dependency), 21 22implementation - makes a dependency available for main classes, tests 23 but will *not* export the dependency for other modules (so their 24 compilation classpath won't contain it). 25 26testImplementation - makes a dependency only available for test classes. 27 28 29Adding a library dependency 30--------------------------- 31 32Let's say we wish to add a dependency on library "foo.bar:baz" in 33version 1.2 to :lucene:core. Let's assume this library is only 34used internally by the project. The :lucene:core project is configured 35by lucene/core/build.gradle and we would add (or modify) the dependency 36block as follows: 37 38dependencies { 39 implementation "foo.bar:baz" 40} 41 42The "implementation" here is a named configuration; we don't need to declare 43it because it is declared for us by the java-library plugin. 44 45In "normal" gradle the version of the dependency would be present 46directly inside the declaration but we use a plugin 47(palantir-consistent-versions) to manage all dependency versions 48from the top-level (so that conflicts can be resolved globally). 49 50If this is the first time "foo.bar:baz" is added to the project, we'd have 51to add its version to "versions.props" file at the top level of the 52checkout: 53 54foo.bar:baz=1.2 55 56and then regenerate the "versions.lock" file using the following 57command: 58 59gradlew --write-locks 60 61IMPORTANT: The versions.lock file will contain the actual version 62of the dependency picked based on other project dependencies and 63their transitive dependencies. This selected version may be 64different from what each of these actually requires (the highest 65version number will be typically selected). To see which dependencies 66require which version of the library use: 67 68gradlew why --hash=... 69 70where the hash code comes from versions.lock file. For example, at 71the time of writing, jackson-databind has the following entry: 72 73com.fasterxml.jackson.core:jackson-databind:2.10.0 (3 constraints: 931a7796) 74 75and "gradlew why --hash=931a7796" prints: 76 77com.fasterxml.jackson.core:jackson-databind:2.10.0 78 projects -> 2.10.0 79 net.thisptr:jackson-jq -> 2.7.0 80 org.carrot2:carrot2-mini -> 2.9.9.3 81 82Once the dependency is added it always makes sense to see the 83tree of all module dependencies and maybe exclude transitive 84dependencies of foo.bar:baz that we won't need. 85 86 87Inspecting current dependencies 88------------------------------- 89 90The tree of dependencies of a project (in all configurations) can 91be dumped by the following command (example): 92 93gradlew -p lucene\analysis\icu dependencies 94 95But this can be a bit overwhelming; we will most likely be interested 96in just the "publicly visible" and "classpath-visible" configurations. 97 98The publicly visible project dependencies (classes shared by other 99modules importing our module) can be displayed with: 100 101gradlew -p lucene\analysis\icu dependencies --configuration api 102 103And the "private" set of dependencies (real classpath) can be dumped 104with: 105 106gradlew -p lucene\analysis\icu dependencies --configuration runtimeClasspath 107 108 109Excluding a transitive dependency 110--------------------------------- 111 112Let's say "foo.bar:baz" has a transitive dependency on project 113"foo.bar:irrelevant" and we know the transitive dependency is not 114crucial for the functioning of "foo.bar:baz". We can exclude it 115by adding an exclusion block to the original declaration: 116 117dependencies { 118 implementation("foo.bar:baz", { 119 exclude group: "foo.bar", module: "irrelevant" 120 }) 121} 122 123Note the brackets - they are important and prevent accidental 124mistakes of applying the exclusion to the wrong scope. 125 126 127Updating dependency checksum and licenses 128----------------------------------------- 129 130The last step is to make sure the licenses, notice files and checksums 131are in place for any new dependencies. This command will print what's 132missing and where: 133 134gradlew licenses 135 136To update JAR checksums for licenses use: 137 138gradlew updateLicenses 139