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.