1# Gradle {#gradle} 2 3Gradle is a popular build tool for Java/Kotlin. Gradle itself doesn't 4currently provide tools to make dependency resolution reproducible, so 5nixpkgs has a proxy designed for intercepting Gradle web requests to 6record dependencies so they can be restored in a reproducible fashion. 7 8## Building a Gradle package {#building-a-gradle-package} 9 10Here's how a typical derivation will look: 11 12```nix 13stdenv.mkDerivation (finalAttrs: { 14 pname = "pdftk"; 15 version = "3.3.3"; 16 17 src = fetchFromGitLab { 18 owner = "pdftk-java"; 19 repo = "pdftk"; 20 tag = "v${finalAttrs.version}"; 21 hash = "sha256-ciKotTHSEcITfQYKFZ6sY2LZnXGChBJy0+eno8B3YHY="; 22 }; 23 24 nativeBuildInputs = [ 25 gradle 26 makeWrapper 27 ]; 28 29 # if the package has dependencies, mitmCache must be set 30 mitmCache = gradle.fetchDeps { 31 inherit (finalAttrs) pname; 32 data = ./deps.json; 33 }; 34 35 # this is required for using mitm-cache on Darwin 36 __darwinAllowLocalNetworking = true; 37 38 gradleFlags = [ "-Dfile.encoding=utf-8" ]; 39 40 # defaults to "assemble" 41 gradleBuildTask = "shadowJar"; 42 43 # will run the gradleCheckTask (defaults to "test") 44 doCheck = true; 45 46 installPhase = '' 47 mkdir -p $out/{bin,share/pdftk} 48 cp build/libs/pdftk-all.jar $out/share/pdftk 49 50 makeWrapper ${lib.getExe jre} $out/bin/pdftk \ 51 --add-flags "-jar $out/share/pdftk/pdftk-all.jar" 52 53 cp ${finalAttrs.src}/pdftk.1 $out/share/man/man1 54 ''; 55 56 meta.sourceProvenance = with lib.sourceTypes; [ 57 fromSource 58 binaryBytecode # mitm cache 59 ]; 60}) 61``` 62 63To update (or initialize) dependencies, run the update script via 64something like `$(nix-build -A <pname>.mitmCache.updateScript)` 65(`nix-build` builds the `updateScript`, `$(...)` runs the script at the 66path printed by `nix-build`). 67 68If your package can't be evaluated using a simple `pkgs.<pname>` 69expression (for example, if your package isn't located in nixpkgs, or if 70you want to override some of its attributes), you will usually have to 71pass `pkg` instead of `pname` to `gradle.fetchDeps`. There are two ways 72of doing so. 73 74The first is to add the derivation arguments required for getting the 75package. Using the pdftk example above: 76 77```nix 78{ 79 lib, 80 stdenv, 81 gradle, 82 # ... 83 pdftk, 84}: 85 86stdenv.mkDerivation (finalAttrs: { 87 # ... 88 mitmCache = gradle.fetchDeps { 89 pkg = pdftk; 90 data = ./deps.json; 91 }; 92}) 93``` 94 95This allows you to `override` any arguments of the `pkg` used for the update script (for example, `pkg = pdftk.override { enableSomeFlag = true };)`. 96 97The second is to use `finalAttrs.finalPackage` like this: 98 99```nix 100stdenv.mkDerivation (finalAttrs: { 101 # ... 102 mitmCache = gradle.fetchDeps { 103 pkg = finalAttrs.finalPackage; 104 data = ./deps.json; 105 }; 106}) 107``` 108The limitation of this method is that you cannot override the `pkg` derivations's arguments. 109 110In the former case, the update script will stay the same even if the derivation is called with different arguments. In the latter case, the update script will change depending on the derivation arguments. It's up to you to decide which one would work best for your derivation. 111 112## Update Script {#gradle-update-script} 113 114The update script does the following: 115 116- Build the derivation's source via `pkgs.srcOnly` 117- Enter a `nix-shell` for the derivation in a `bwrap` sandbox (the 118 sandbox is only used on Linux) 119- Set the `IN_GRADLE_UPDATE_DEPS` environment variable to `1` 120- Run the derivation's `unpackPhase`, `patchPhase`, `configurePhase` 121- Run the derivation's `gradleUpdateScript` (the Gradle setup hook sets 122 a default value for it, which runs `preBuild`, `preGradleUpdate` 123 hooks, fetches the dependencies using `gradleUpdateTask`, and finally 124 runs the `postGradleUpdate` hook) 125- Finally, store all of the fetched files' hashes in the lockfile. They 126 may be `.jar`/`.pom` files from Maven repositories, or they may be 127 files otherwise used for building the package. 128 129`fetchDeps` takes the following arguments: 130 131- `attrPath` - the path to the package in nixpkgs (for example, 132 `"javaPackages.openjfx22"`). Used for update script metadata. 133- `pname` - an alias for `attrPath` for convenience. This is what you 134 will generally use instead of `pkg` or `attrPath`. 135- `pkg` - the package to be used for fetching the dependencies. Defaults 136 to `getAttrFromPath (splitString "." attrPath) pkgs`. 137- `bwrapFlags` - allows you to override bwrap flags (only relevant for 138 downstream, non-nixpkgs projects) 139- `data` - path to the dependencies lockfile (can be relative to the 140 package, can be absolute). In nixpkgs, it's discouraged to have the 141 lockfiles be named anything other `deps.json`, consider creating 142 subdirectories if your package requires multiple `deps.json` files. 143 144## Environment {#gradle-environment} 145 146The Gradle setup hook accepts the following environment variables: 147 148- `mitmCache` - the MITM proxy cache imported using `gradle.fetchDeps` 149- `gradleFlags` - command-line flags to be used for every Gradle 150 invocation (this simply registers a function that uses the necessary 151 flags). 152 - You can't use `gradleFlags` for flags that contain spaces, in that 153 case you must add `gradleFlagsArray+=("-flag with spaces")` to the 154 derivation's bash code instead. 155 - If you want to build the package using a specific Java version, you 156 can pass `"-Dorg.gradle.java.home=${jdk}"` as one of the flags. 157- `gradleBuildTask` - the Gradle task (or tasks) to be used for building 158 the package. Defaults to `assemble`. 159- `gradleCheckTask` - the Gradle task (or tasks) to be used for checking 160 the package if `doCheck` is set to `true`. Defaults to `test`. 161- `gradleUpdateTask` - the Gradle task (or tasks) to be used for 162 fetching all of the package's dependencies in 163 `mitmCache.updateScript`. Defaults to `nixDownloadDeps`. 164- `gradleUpdateScript` - the code to run for fetching all of the 165 package's dependencies in `mitmCache.updateScript`. Defaults to 166 running the `preBuild` and `preGradleUpdate` hooks, running the 167 `gradleUpdateTask`, and finally running the `postGradleUpdate` hook. 168- `gradleInitScript` - path to the `--init-script` to pass to Gradle. By 169 default, a simple init script that enables reproducible archive 170 creation is used. 171 - Note that reproducible archives might break some builds. One example 172 of an error caused by it is `Could not create task ':jar'. Replacing 173 an existing task that may have already been used by other plugins is 174 not supported`. If you get such an error, the easiest "fix" is 175 disabling reproducible archives altogether by setting 176 `gradleInitScript` to something like `writeText 177 "empty-init-script.gradle" ""` 178- `enableParallelBuilding` / `enableParallelChecking` / 179 `enableParallelUpdating` - pass `--parallel` to Gradle in the 180 build/check phase or in the update script. Defaults to true. If the 181 build fails for mysterious reasons, consider setting this to false. 182- `dontUseGradleConfigure` / `dontUseGradleBuild` / `dontUseGradleCheck` 183 \- force disable the Gradle setup hook for certain phases. 184 - Note that if you disable the configure hook, you may face issues 185 such as `Failed to load native library 'libnative-platform.so'`, 186 because the configure hook is responsible for initializing Gradle.