Generate Nix expressions which build Gradle-based projects.
Nix is an OS-agnostic package manager, a language-agnostic build system, and a bespoke programming language. One of its unique features is that it is purely functional; a “package” is a function which accepts inputs (source code, configuration, etc) and produces an output (binaries, a Java JAR, documentation, really anything).
One benefit of a functional build system is reproducibility. If you specify your inputs precisely, and take care not to introduce impurities—such as files retrieved over a network without tracking their content—you will receive, byte-for-byte, the exact output as someone else running the same function over the same inputs.
Gradle is not a functional build system. Most Gradle-based projects will produce highly variable outputs depending on a host of impure inputs, including:
- The JVM hosting the build
- The Gradle installation running the build
- Any usage of dynamic version constraints for dependencies
- SNAPSHOT dependencies
- Environment variables and command-line options
- Artifacts cached on the system hosting the build
gradle2nix
helps to solve this problem by leveraging Nix to control
the most common inputs to a Gradle build. When run on a project, it
will record all dependencies for both the build environment (including
plugins
and buildscript
blocks) and the project, and provide a Nix
expression to run the build given these dependencies. The build itself
is then run in a sandbox, where only content-tracked network requests
are allowed to fetch dependencies, and a local Maven repository is
created on-the-fly to host the dependency artifacts somewhere Gradle
can resolve them without a network.
This tool is useful for both development and packaging. You can use
gradle2nix
to:
- Create isolated and reproducible development environments that work anywhere Nix itself can run;
- Reduce or eliminate flakiness and maintenance headaches from CI/CD pipelines
- Distribute a recipe which can reliably build a Gradle project in repositories such as the Nix Package Collection.
A Nix expression (generated by gradle2nix
itself) is provided for
convenience. The following expression will fetch and build the latest
version of this package:
import (fetchTarball "https://github.com/tadfisher/gradle2nix/archive/master.tar.gz") {}
If this expression is in, say, gradle2nix.nix
, gradle2nix
can be
built and placed in .//result
with the following:
nix build -f gradle2nix.nix
You can also use the following one-liners to build or install
gradle2nix
in your user profile:
# Build and place in ./result/ nix build -f "https://github.com/tadfisher/gradle2nix/archive/master.tar.gz" # Build and install in the user profile nix-env -if "https://github.com/tadfisher/gradle2nix/archive/master.tar.gz"
gradle2nix
is not yet packaged in nixpkgs
itself, but work is
in progress.
A flake.nix is provided for those using Nix flakes. For example, the
following will build and run gradle2nix
with the arguments provided
after --
:
nix run github:tadfisher/gradle2nix -- --help
Usage: gradle2nix [OPTIONS] [PROJECT-DIR] Options: -g, --gradle-version VERSION Use a specific Gradle version -a, --gradle-args ARGS Extra arguments to pass to Gradle -c, --configuration NAME Add a configuration to resolve (default: all configurations) -i, --include DIR Add an additional project to include -p, --project PATH Only resolve these subproject paths, e.g. ':', or ':sub:project' (default: all projects) -o, --out-dir DIR Path to write generated files (default: PROJECT-DIR) -e, --env FILENAME Prefix for environment files (.json and .nix) (default: gradle-env) -b, --build-src / -nb, --no-build-src Include buildSrc project (default: true) -q, --quiet Disable logging -h, --help Show this message and exit Arguments: PROJECT-DIR Path to the project root (default: .)
Simply running gradle2nix
in the root directory of a project should
be enough for most projects. This will produce two files, by default
called gradle-env.json
and gradle-env.nix
, which contain the
pinned dependencies for the project and a standard build expression
which can be imported or called by other Nix expressions. An example
of such an expression can be found in this project’s default.nix.
By default, if the project has configured the Gradle wrapper, that
version will be detected and pinned; otherwise, the version of Gradle
installed on your system will be pinned. You can override this with
the --gradle-version
argument, which also avoids the need to have
Gradle installed.
gradle2nix -g 6.1
If you want to resolve only a subset of projects in a multi-project
build, add the --project
option for each project. For example, in a
project where you only want to build the subprojects :app
and
:widget
:
gradle2nix -p :app -p :widget
Any project dependencies will be also be included when pinning dependency artifacts.
Bug reports and feature requests are encouraged.
Code contributions are also encouraged. Please review the test cases in the fixtures directory and create a new one to reproduce any fixes or test new features. See the existing compatibility tests for examples of testing with these fixtures.
gradle2nix
is licensed under the MIT License.