about summary refs log tree commit diff
path: root/doc/languages-frameworks/gradle.section.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/languages-frameworks/gradle.section.md')
-rw-r--r--doc/languages-frameworks/gradle.section.md189
1 files changed, 189 insertions, 0 deletions
diff --git a/doc/languages-frameworks/gradle.section.md b/doc/languages-frameworks/gradle.section.md
new file mode 100644
index 0000000000000..b2058ef87491b
--- /dev/null
+++ b/doc/languages-frameworks/gradle.section.md
@@ -0,0 +1,189 @@
+# Gradle {#gradle}
+
+Gradle is a popular build tool for Java/Kotlin. Gradle itself doesn't
+currently provide tools to make dependency resolution reproducible, so
+nixpkgs has a proxy designed for intercepting Gradle web requests to
+record dependencies so they can be restored in a reproducible fashion.
+
+## Building a Gradle package {#building-a-gradle-package}
+
+Here's how a typical derivation will look like:
+
+```nix
+stdenv.mkDerivation (finalAttrs: {
+  pname = "pdftk";
+  version = "3.3.3";
+
+  src = fetchFromGitLab {
+    owner = "pdftk-java";
+    repo = "pdftk";
+    rev = "v${finalAttrs.version}";
+    hash = "sha256-ciKotTHSEcITfQYKFZ6sY2LZnXGChBJy0+eno8B3YHY=";
+  };
+
+  nativeBuildInputs = [ gradle ];
+
+  # if the package has dependencies, mitmCache must be set
+  mitmCache = gradle.fetchDeps {
+    inherit (finalAttrs) pname;
+    data = ./deps.json;
+  };
+
+  # this is required for using mitm-cache on Darwin
+  __darwinAllowLocalNetworking = true;
+
+  gradleFlags = [ "-Dfile.encoding=utf-8" ];
+
+  # defaults to "assemble"
+  gradleBuildTask = "shadowJar";
+
+  # will run the gradleCheckTask (defaults to "test")
+  doCheck = true;
+
+  installPhase = ''
+    mkdir -p $out/{bin,share/pdftk}
+    cp build/libs/pdftk-all.jar $out/share/pdftk
+
+    makeWrapper ${jre}/bin/java $out/bin/pdftk \
+      --add-flags "-jar $out/share/pdftk/pdftk-all.jar"
+
+    cp ${finalAttrs.src}/pdftk.1 $out/share/man/man1
+  '';
+
+  meta.sourceProvenance = with lib.sourceTypes; [
+    fromSource
+    binaryBytecode # mitm cache
+  ];
+})
+```
+
+To update (or initialize) dependencies, run the update script via
+something like `$(nix-build -A <pname>.mitmCache.updateScript)`
+(`nix-build` builds the `updateScript`, `$(...)` runs the script at the
+path printed by `nix-build`).
+
+If your package can't be evaluated using a simple `pkgs.<pname>`
+expression (for example, if your package isn't located in nixpkgs, or if
+you want to override some of its attributes), you will usually have to
+pass `pkg` instead of `pname` to `gradle.fetchDeps`. There are two ways
+of doing it.
+
+The first is to add the derivation arguments required for getting the
+package. Using the pdftk example above:
+
+```nix
+{ lib
+, stdenv
+# ...
+, pdftk
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  # ...
+  mitmCache = gradle.fetchDeps {
+    pkg = pdftk;
+    data = ./deps.json;
+  };
+})
+```
+
+This allows you to `override` any arguments of the `pkg` used for
+the update script (for example, `pkg = pdftk.override { enableSomeFlag =
+true };`), so this is the preferred way.
+
+The second is to create a `let` binding for the package, like this:
+
+```nix
+let self = stdenv.mkDerivation {
+  # ...
+  mitmCache = gradle.fetchDeps {
+    pkg = self;
+    data = ./deps.json;
+  };
+}; in self
+```
+
+This is useful if you can't easily pass the derivation as its own
+argument, or if your `mkDerivation` call is responsible for building
+multiple packages.
+
+In 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.
+
+## Update Script {#gradle-update-script}
+
+The update script does the following:
+
+- Build the derivation's source via `pkgs.srcOnly`
+- Enter a `nix-shell` for the derivation in a `bwrap` sandbox (the
+  sandbox is only used on Linux)
+- Set the `IN_GRADLE_UPDATE_DEPS` environment variable to `1`
+- Run the derivation's `unpackPhase`, `patchPhase`, `configurePhase`
+- Run the derivation's `gradleUpdateScript` (the Gradle setup hook sets
+  a default value for it, which runs `preBuild`, `preGradleUpdate`
+  hooks, fetches the dependencies using `gradleUpdateTask`, and finally
+  runs the `postGradleUpdate` hook)
+- Finally, store all of the fetched files' hashes in the lockfile. They
+  may be `.jar`/`.pom` files from Maven repositories, or they may be
+  files otherwise used for building the package.
+
+`fetchDeps` takes the following arguments:
+
+- `attrPath` - the path to the package in nixpkgs (for example,
+  `"javaPackages.openjfx22"`). Used for update script metadata.
+- `pname` - an alias for `attrPath` for convenience. This is what you
+  will generally use instead of `pkg` or `attrPath`.
+- `pkg` - the package to be used for fetching the dependencies. Defaults
+  to `getAttrFromPath (splitString "." attrPath) pkgs`.
+- `bwrapFlags` - allows you to override bwrap flags (only relevant for
+  downstream, non-nixpkgs projects)
+- `data` - path to the dependencies lockfile (can be relative to the
+  package, can be absolute). In nixpkgs, it's discouraged to have the
+  lockfiles be named anything other `deps.json`, consider creating
+  subdirectories if your package requires multiple `deps.json` files.
+
+## Environment {#gradle-environment}
+
+The Gradle setup hook accepts the following environment variables:
+
+- `mitmCache` - the MITM proxy cache imported using `gradle.fetchDeps`
+- `gradleFlags` - command-line flags to be used for every Gradle
+  invocation (this simply registers a function that uses the necessary
+  flags).
+  - You can't use `gradleFlags` for flags that contain spaces, in that
+    case you must add `gradleFlagsArray+=("-flag with spaces")` to the
+    derivation's bash code instead.
+  - If you want to build the package using a specific Java version, you
+    can pass `"-Dorg.gradle.java.home=${jdk}"` as one of the flags.
+- `gradleBuildTask` - the Gradle task (or tasks) to be used for building
+  the package. Defaults to `assemble`.
+- `gradleCheckTask` - the Gradle task (or tasks) to be used for checking
+  the package if `doCheck` is set to `true`. Defaults to `test`.
+- `gradleUpdateTask` - the Gradle task (or tasks) to be used for
+  fetching all of the package's dependencies in
+  `mitmCache.updateScript`. Defaults to `nixDownloadDeps`.
+- `gradleUpdateScript` - the code to run for fetching all of the
+  package's dependencies in `mitmCache.updateScript`. Defaults to
+  running the `preBuild` and `preGradleUpdate` hooks, running the
+  `gradleUpdateTask`, and finally running the `postGradleUpdate` hook.
+- `gradleInitScript` - path to the `--init-script` to pass to Gradle. By
+  default, a simple init script that enables reproducible archive
+  creation is used.
+  - Note that reproducible archives might break some builds. One example
+    of an error caused by it is `Could not create task ':jar'. Replacing
+    an existing task that may have already been used by other plugins is
+    not supported`. If you get such an error, the easiest "fix" is
+    disabling reproducible archives altogether by setting
+    `gradleInitScript` to something like `writeText
+    "empty-init-script.gradle" ""`
+- `enableParallelBuilding` / `enableParallelChecking` /
+  `enableParallelUpdating` - pass `--parallel` to Gradle in the
+  build/check phase or in the update script. Defaults to true. If the
+  build fails for mysterious reasons, consider setting this to false.
+- `dontUseGradleConfigure` / `dontUseGradleBuild` / `dontUseGradleCheck`
+  \- force disable the Gradle setup hook for certain phases.
+  - Note that if you disable the configure hook, you may face issues
+    such as `Failed to load native library 'libnative-platform.so'`,
+    because the configure hook is responsible for initializing Gradle.