Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Packaging Gradle-based applications #17342

Closed
bobvanderlinden opened this issue Jul 28, 2016 · 30 comments
Closed

Packaging Gradle-based applications #17342

bobvanderlinden opened this issue Jul 28, 2016 · 30 comments
Labels
0.kind: enhancement Add something new 6.topic: java Including JDK, tooling, other languages, other VMs

Comments

@bobvanderlinden
Copy link
Member

Issue description

I have a (closed) application that I'd like to package and place on my NixOS server. The application can be built using Gradle, however since Gradle downloads its dependencies online it is unable to be build using Nix as-is.

It seemed all application that are based on Java/Ant/Maven/Gradle are being packaged based on binaries, instead of the source. Is this the recommended way to use Java-based applications on Nix?

While trying to find a solution, I have found mvn2nix-maven-plugin, but it was unclear how to use it for other projects. Especially the ones built with Gradle.

@bennofs bennofs added the 0.kind: enhancement Add something new label Aug 2, 2016
@spacekitteh
Copy link
Contributor

Seconding this. I'd really like to figure this out.

@NeQuissimus
Copy link
Member

There is #20444 :-)

@spacekitteh
Copy link
Contributor

Aye, but Gradle is needed for Android apps

@auntieNeo
Copy link
Contributor

I am especially interested in building Android apps with Gradle. Recent apps created with Android studio no longer work with ant.

I wonder if androidenv can be extended to work with the Gradle wrapper. Or maybe that's not a viable approach.

@bobvanderlinden
Copy link
Member Author

bobvanderlinden commented Jun 4, 2018

Gradle 4.8 was just released. It includes locking of versions, which might be useful for Nix:

https://docs.gradle.org/current/release-notes.html#locking-of-dynamic-dependencies

@tadfisher
Copy link
Contributor

@bobvanderlinden Very cool, a gradle2nix tool is feasible now.

@bobvanderlinden
Copy link
Member Author

The lock file only includes the groupId, artifactId and the version. See https://docs.gradle.org/current/userguide/dependency_locking.html#_lock_state_location_and_format

We still need a way to know the URLs for these packages.

@tadfisher
Copy link
Contributor

@bobvanderlinden That's fine. What I'd do is make a Gradle plugin that emits a Nix configuration for a task, and apply it using gradle --init-script. This would actually work without dependency locking.

@bobvanderlinden
Copy link
Member Author

Oh wow. I didn't know Gradle could do that. Nice.

https://docs.gradle.org/current/userguide/init_scripts.html#sec:basic_usage

Register build listeners. External tools that wish to listen to Gradle events might find this useful.

Though I cannot find how to hook into the downloader.

Another useful plugin is one that downloads all dependencies:

https://github.com/mdietrichstein/gradle-offline-dependencies-plugin

@lheckemann
Copy link
Member

@tadfisher
Copy link
Contributor

tadfisher commented Sep 22, 2018

So there's a couple of approaches we can take with this.

We could write a gradle2nix tool which simply outputs the set of artifacts including URLs and hashes. I've started on a plugin that can be applied from an init script, and it can successfully dump artifact information (groupId, artifactId, version, url, sha256) from a Gradle configuration. However, this is only easily doable for Maven repositories; dumping artifacts fetched from Ivy repositories require using internal APIs which undergo lots of churn. This comes down to the fact that Ivy repos do not expose their artifactPatterns, ivyPatterns, and m2compatible fields, which is easily worked around but makes me uneasy.

Another issue with a Gradle plugin solution is that Gradle does not expose any information about dependency resolution, at least not without extreme hacking. The naive implementation, then, would provide a set of source URLs for each artifact, as we have no way of knowing which repository Gradle actually fetched an artifact from without using internal APIs. This is all doable, but ugly. Note that the gradle-offline-dependencies-plugin linked earlier uses said internal APIs only to fetch artifacts into a local repository, and still must use internal APIs to do so (and broke in 4.9); it does not attempt to determine the source URLs/patterns for repositories or artifacts.

So I've used another approach recently in https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/security/jd-gui/default.nix, which uses Gradle itself to fetch dependencies, then copies those dependencies from its cache into an offline Maven repository. The entire repository is hashed. This was actually pulled from the mucommander derivation which applied this hack a long time ago to package an application built with Gradle.

This approach is far from pure, however, as it cannot be used with sandboxing. So I propose creating a fetchGradleDependencies function which can be used in a srcs attribute, and a buildGradlePackage function which wraps mkDerivation and appends a fetchGradleDependencies call to buildInputs. This should let us fetch and create the offline repository in sandbox builds.

@deliciouslytyped
Copy link
Contributor

deliciouslytyped commented Mar 27, 2019

Any news here?
Edit: continued:
Ghidra will probably use gradle for it's build system if and when it gets released.
At the least, it seems to be used for building extensions (and basically the entire app is a framework of extensions).

@tadfisher
Copy link
Contributor

Here's a POC for a gradle2nix tool: https://github.com/tadfisher/gradle2nix

It should be able to build itself with the included default.nix. Use it with gradle2nix in a project root.

There are a few pitfalls that I'm working out:

  • It builds against Gradle 5.3, but there are a couple of APIs that it uses that aren't available on older Gradle versions, so it only supports Gradle 5.3+ right now.
  • It only supports Maven dependencies. Ivy support is slightly less trivial but I will add it after writing tests.
  • It resolves plugin marker dependencies and plugin repositories with internal APIs, which might be unavoidable.
  • It's currently a gradle plugin in order to resolve plugins. However, this requires application via an init script. It could potentially resolve plugins as a settings plugin, and the project dependency resolution could be split out into a project plugin.
  • I haven't looked into resolving buildSrc dependencies or overriding repos for buildSrc projects.

@tadfisher
Copy link
Contributor

I've reworked gradle2nix to use the Gradle Tooling API, so the implementation is a bit cleaner.

  • It's now compatible with Gradle 4.4 and up, with a test suite for regressions.
  • I've added some rudimentary support for included builds and buildSrc, but I haven't gotten around to testing it.

@deliciouslytyped
Copy link
Contributor

@tadfisher This looks pretty good, I'm not intimately familiar with gradle, how do I run this if I want to package something?

@tadfisher
Copy link
Contributor

You should be able to build the gradle2nix application using the included default.nix script, then just run [result]/bin/gradle2nix in a Gradle project directory. This will generate a gradle-env.json and gradle-env.nix pair. You can then import the Nix expression and use it to build the project. See default.nix in the gradle2nix project itself for an example.

@NorfairKing
Copy link
Contributor

+1

@deliciouslytyped
Copy link
Contributor

For later reference, here is an example of something using Gradle without any extra fancy tooling (I think) #72306

@tadfisher
Copy link
Contributor

@deliciouslytyped Unfortunately, that solution will break whenever one of its SNAPSHOT dependencies publishes a new version. In general, you can't make a fixed-output derivation from the dependencies fetched for a build, because Gradle allows dynamic dependency versions and can resolve different artifacts from run to run. Therefore, you need tooling to extract the resolved artifact sources in order to make the build reproducible.

@ghost
Copy link

ghost commented Jan 10, 2020

I made an attempt to use gradle2nix in nixpkgs: #77422

@stale
Copy link

stale bot commented Jul 8, 2020

Hello, I'm a bot and I thank you in the name of the community for opening this issue.

To help our human contributors focus on the most-relevant reports, I check up on old issues to see if they're still relevant. This issue has had no activity for 180 days, and so I marked it as stale, but you can rest assured it will never be closed by a non-human.

The community would appreciate your effort in checking if the issue is still valid. If it isn't, please close it.

If the issue persists, and you'd like to remove the stale label, you simply need to leave a comment. Your comment can be as simple as "still important to me". If you'd like it to get more attention, you can ask for help by searching for maintainers and people that previously touched related code and @ mention them in a comment. You can use Git blame or GitHub's web interface on the relevant files to find them.

Lastly, you can always ask for help at our Discourse Forum or at #nixos' IRC channel.

@stale stale bot added the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Jul 8, 2020
@NorfairKing
Copy link
Contributor

"still important to me"

@stale stale bot removed the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Jul 8, 2020
@stale
Copy link

stale bot commented Jan 4, 2021

I marked this as stale due to inactivity. → More info

@stale stale bot added the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Jan 4, 2021
@doronbehar
Copy link
Contributor

doronbehar commented Jan 4, 2021 via email

@stale stale bot removed the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Jan 4, 2021
@gytis-ivaskevicius
Copy link
Contributor

gytis-ivaskevicius commented Apr 8, 2021

Welp, this is the moment I have been training my whole life. Ahem... It is still important!!

Edit: Apparently I am blind, either that or I do not understand meaning of the word "removed". Sorry for ping

@randomnetcat
Copy link
Contributor

Unfortunately, that solution will break whenever one of its SNAPSHOT dependencies publishes a new version. In general, you can't make a fixed-output derivation from the dependencies fetched for a build, because Gradle allows dynamic dependency versions and can resolve different artifacts from run to run. Therefore, you need tooling to extract the resolved artifact sources in order to make the build reproducible.

As of Gradle 6.2, Gradle can verify hashes and signatures of artifacts and metadata. See https://docs.gradle.org/current/userguide/dependency_verification.html

@bobvanderlinden
Copy link
Member Author

Some updates:

#272380 is an effort to have a setup hook available for gradle projects in nixpkgs.

NixOS/GSoC#19 is a project proposal for Google Summer of Code to create better gradle tooling.

@nixos-discourse
Copy link

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/buildgradleapplication-a-simpler-approach-to-packaging-gradle-projects/46012/3

@tadfisher
Copy link
Contributor

gradle2nix v2 is available for testing, with a novel approach to extracting artifact information by leveraging Gradle's module cache. I have successfully compiled Kotlin from source with it, which is no small feat. Please give it a try, and I intend to contribute this to nixpkgs if all goes well.

@Atemu
Copy link
Member

Atemu commented Oct 24, 2024

#272380 has been merged and useable for a while now.

@Atemu Atemu closed this as completed Oct 24, 2024
@tomodachi94 tomodachi94 added the 6.topic: java Including JDK, tooling, other languages, other VMs label Nov 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
0.kind: enhancement Add something new 6.topic: java Including JDK, tooling, other languages, other VMs
Projects
None yet
Development

No branches or pull requests