From 80a5a929c5af46712f83fb71b7b812d63b19f89c Mon Sep 17 00:00:00 2001 From: Tomodachi94 Date: Sat, 23 Nov 2024 19:28:15 +0000 Subject: [PATCH] maven.buildMaven: drop This was discouraged in https://github.com/NixOS/nixpkgs/pull/240553 Nobody is using it in-tree; the upstream repository provides the same builder in an output of its flake, for out-of-tree consumers: https://github.com/fzakaria/mvn2nix --- doc/languages-frameworks/maven.section.md | 357 ------------------ doc/redirects.json | 24 -- .../manual/release-notes/rl-2505.section.md | 5 + pkgs/by-name/ma/maven/build-maven.nix | 88 ----- pkgs/by-name/ma/maven/package.nix | 4 +- 5 files changed, 6 insertions(+), 472 deletions(-) delete mode 100644 pkgs/by-name/ma/maven/build-maven.nix diff --git a/doc/languages-frameworks/maven.section.md b/doc/languages-frameworks/maven.section.md index d6c8357785e35..a653f1ed1e9fd 100644 --- a/doc/languages-frameworks/maven.section.md +++ b/doc/languages-frameworks/maven.section.md @@ -80,360 +80,3 @@ To make sure that your package does not add extra manual effort when upgrading M ``` -## Manually using `mvn2nix` {#maven-mvn2nix} -::: {.warning} -This way is no longer recommended; see [](#maven-buildmavenpackage) for the simpler and preferred way. -::: - -For the purposes of this example let's consider a very basic Maven project with the following `pom.xml` with a single dependency on [emoji-java](https://github.com/vdurmont/emoji-java). - -```xml - - - 4.0.0 - io.github.fzakaria - maven-demo - 1.0 - jar - NixOS Maven Demo - - - - com.vdurmont - emoji-java - 5.1.1 - - - -``` - -Our main class file will be very simple: - -```java -import com.vdurmont.emoji.EmojiParser; - -public class Main { - public static void main(String[] args) { - String str = "NixOS :grinning: is super cool :smiley:!"; - String result = EmojiParser.parseToUnicode(str); - System.out.println(result); - } -} -``` - -You find this demo project at [https://github.com/fzakaria/nixos-maven-example](https://github.com/fzakaria/nixos-maven-example). - -### Solving for dependencies {#solving-for-dependencies} - -#### buildMaven with NixOS/mvn2nix-maven-plugin {#buildmaven-with-nixosmvn2nix-maven-plugin} -`buildMaven` is an alternative method that tries to follow similar patterns of other programming languages by generating a lock file. It relies on the maven plugin [mvn2nix-maven-plugin](https://github.com/NixOS/mvn2nix-maven-plugin). - -First you generate a `project-info.json` file using the maven plugin. - -> This should be executed in the project's source repository or be told which `pom.xml` to execute with. - -```bash -# run this step within the project's source repository -❯ mvn org.nixos.mvn2nix:mvn2nix-maven-plugin:mvn2nix - -❯ cat project-info.json | jq | head -{ - "project": { - "artifactId": "maven-demo", - "groupId": "org.nixos", - "version": "1.0", - "classifier": "", - "extension": "jar", - "dependencies": [ - { - "artifactId": "maven-resources-plugin", -``` - -This file is then given to the `buildMaven` function, and it returns 2 attributes. - -**`repo`**: - A Maven repository that is a symlink farm of all the dependencies found in the `project-info.json` - - -**`build`**: - A simple derivation that runs through `mvn compile` & `mvn package` to build the JAR. You may use this as inspiration for more complicated derivations. - -Here is an [example](https://github.com/fzakaria/nixos-maven-example/blob/main/build-maven-repository.nix) of building the Maven repository - -```nix -{ pkgs ? import { } }: -with pkgs; -(buildMaven ./project-info.json).repo -``` - -The benefit over the _double invocation_ as we will see below, is that the _/nix/store_ entry is a _linkFarm_ of every package, so that changes to your dependency set doesn't involve downloading everything from scratch. - -```bash -❯ tree $(nix-build --no-out-link build-maven-repository.nix) | head -/nix/store/g87va52nkc8jzbmi1aqdcf2f109r4dvn-maven-repository -├── antlr -│   └── antlr -│   └── 2.7.2 -│   ├── antlr-2.7.2.jar -> /nix/store/d027c8f2cnmj5yrynpbq2s6wmc9cb559-antlr-2.7.2.jar -│   └── antlr-2.7.2.pom -> /nix/store/mv42fc5gizl8h5g5vpywz1nfiynmzgp2-antlr-2.7.2.pom -├── avalon-framework -│   └── avalon-framework -│   └── 4.1.3 -│   ├── avalon-framework-4.1.3.jar -> /nix/store/iv5fp3955w3nq28ff9xfz86wvxbiw6n9-avalon-framework-4.1.3.jar -``` - -#### Double Invocation {#double-invocation} -::: {.note} -This pattern is the simplest but may cause unnecessary rebuilds due to the output hash changing. -::: - -The double invocation is a _simple_ way to get around the problem that `nix-build` may be sandboxed and have no Internet connectivity. - -It treats the entire Maven repository as a single source to be downloaded, relying on Maven's dependency resolution to satisfy the output hash. This is similar to fetchers like `fetchgit`, except it has to run a Maven build to determine what to download. - -The first step will be to build the Maven project as a fixed-output derivation in order to collect the Maven repository -- below is an [example](https://github.com/fzakaria/nixos-maven-example/blob/main/double-invocation-repository.nix). - -::: {.note} -Traditionally the Maven repository is at `~/.m2/repository`. We will override this to be the `$out` directory. -::: - -```nix -{ lib, stdenv, maven }: -stdenv.mkDerivation { - name = "maven-repository"; - buildInputs = [ maven ]; - src = ./.; # or fetchFromGitHub, cleanSourceWith, etc - buildPhase = '' - mvn package -Dmaven.repo.local=$out - ''; - - # keep only *.{pom,jar,sha1,nbm} and delete all ephemeral files with lastModified timestamps inside - installPhase = '' - find $out -type f \ - -name \*.lastUpdated -or \ - -name resolver-status.properties -or \ - -name _remote.repositories \ - -delete - ''; - - # don't do any fixup - dontFixup = true; - outputHashAlgo = null; - outputHashMode = "recursive"; - # replace this with the correct SHA256 - outputHash = lib.fakeHash; -} -``` - -The build will fail, and tell you the expected `outputHash` to place. When you've set the hash, the build will return with a `/nix/store` entry whose contents are the full Maven repository. - -::: {.warning} -Some additional files are deleted that would cause the output hash to change potentially on subsequent runs. -::: - -```bash -❯ tree $(nix-build --no-out-link double-invocation-repository.nix) | head -/nix/store/8kicxzp98j68xyi9gl6jda67hp3c54fq-maven-repository -├── backport-util-concurrent -│   └── backport-util-concurrent -│   └── 3.1 -│   ├── backport-util-concurrent-3.1.pom -│   └── backport-util-concurrent-3.1.pom.sha1 -├── classworlds -│   └── classworlds -│   ├── 1.1 -│   │   ├── classworlds-1.1.jar -``` - -If your package uses _SNAPSHOT_ dependencies or _version ranges_; there is a strong likelihood that over-time your output hash will change since the resolved dependencies may change. Hence this method is less recommended then using `buildMaven`. - -### Building a JAR {#building-a-jar} - -Regardless of which strategy is chosen above, the step to build the derivation is the same. - -```nix -{ stdenv, maven, callPackage }: -# pick a repository derivation, here we will use buildMaven -let repository = callPackage ./build-maven-repository.nix { }; -in stdenv.mkDerivation rec { - pname = "maven-demo"; - version = "1.0"; - - src = builtins.fetchTarball "https://github.com/fzakaria/nixos-maven-example/archive/main.tar.gz"; - buildInputs = [ maven ]; - - buildPhase = '' - echo "Using repository ${repository}" - mvn --offline -Dmaven.repo.local=${repository} package; - ''; - - installPhase = '' - install -Dm644 target/${pname}-${version}.jar $out/share/java - ''; -} -``` - -::: {.tip} -We place the library in `$out/share/java` since JDK package has a _stdenv setup hook_ that adds any JARs in the `share/java` directories of the build inputs to the CLASSPATH environment. -::: - -```bash -❯ tree $(nix-build --no-out-link build-jar.nix) -/nix/store/7jw3xdfagkc2vw8wrsdv68qpsnrxgvky-maven-demo-1.0 -└── share - └── java - └── maven-demo-1.0.jar - -2 directories, 1 file -``` - -### Runnable JAR {#runnable-jar} - -The previous example builds a `jar` file but that's not a file one can run. - -You need to use it with `java -jar $out/share/java/output.jar` and make sure to provide the required dependencies on the classpath. - -The following explains how to use `makeWrapper` in order to make the derivation produce an executable that will run the JAR file you created. - -We will use the same repository we built above (either _double invocation_ or _buildMaven_) to setup a CLASSPATH for our JAR. - -The following two methods are more suited to Nix then building an [UberJar](https://imagej.net/Uber-JAR) which may be the more traditional approach. - -#### CLASSPATH {#classpath} - -This method is ideal if you are providing a derivation for _nixpkgs_ and don't want to patch the project's `pom.xml`. - -We will read the Maven repository and flatten it to a single list. This list will then be concatenated with the _CLASSPATH_ separator to create the full classpath. - -We make sure to provide this classpath to the `makeWrapper`. - -```nix -{ stdenv, maven, callPackage, makeWrapper, jre }: -let - repository = callPackage ./build-maven-repository.nix { }; -in stdenv.mkDerivation rec { - pname = "maven-demo"; - version = "1.0"; - - src = builtins.fetchTarball - "https://github.com/fzakaria/nixos-maven-example/archive/main.tar.gz"; - nativeBuildInputs = [ makeWrapper ]; - buildInputs = [ maven ]; - - buildPhase = '' - echo "Using repository ${repository}" - mvn --offline -Dmaven.repo.local=${repository} package; - ''; - - installPhase = '' - mkdir -p $out/bin - - classpath=$(find ${repository} -name "*.jar" -printf ':%h/%f'); - install -Dm644 target/${pname}-${version}.jar $out/share/java - # create a wrapper that will automatically set the classpath - # this should be the paths from the dependency derivation - makeWrapper ${jre}/bin/java $out/bin/${pname} \ - --add-flags "-classpath $out/share/java/${pname}-${version}.jar:''${classpath#:}" \ - --add-flags "Main" - ''; -} -``` - -#### MANIFEST file via Maven Plugin {#manifest-file-via-maven-plugin} - -This method is ideal if you are the project owner and want to change your `pom.xml` to set the CLASSPATH within it. - -Augment the `pom.xml` to create a JAR with the following manifest: - -```xml - - - - maven-jar-plugin - - - - true - ../../repository/ - repository - Main - - - . - - - - - - -``` - -The above plugin instructs the JAR to look for the necessary dependencies in the `lib/` relative folder. The layout of the folder is also in the _maven repository_ style. - -```bash -❯ unzip -q -c $(nix-build --no-out-link runnable-jar.nix)/share/java/maven-demo-1.0.jar META-INF/MANIFEST.MF - -Manifest-Version: 1.0 -Archiver-Version: Plexus Archiver -Built-By: nixbld -Class-Path: . ../../repository/com/vdurmont/emoji-java/5.1.1/emoji-jav - a-5.1.1.jar ../../repository/org/json/json/20170516/json-20170516.jar -Created-By: Apache Maven 3.6.3 -Build-Jdk: 1.8.0_265 -Main-Class: Main -``` - -We will modify the derivation above to add a symlink to our repository so that it's accessible to our JAR during the `installPhase`. - -```nix -{ stdenv, maven, callPackage, makeWrapper, jre }: -# pick a repository derivation, here we will use buildMaven -let repository = callPackage ./build-maven-repository.nix { }; -in stdenv.mkDerivation rec { - pname = "maven-demo"; - version = "1.0"; - - src = builtins.fetchTarball - "https://github.com/fzakaria/nixos-maven-example/archive/main.tar.gz"; - nativeBuildInputs = [ makeWrapper ]; - buildInputs = [ maven ]; - - buildPhase = '' - echo "Using repository ${repository}" - mvn --offline -Dmaven.repo.local=${repository} package; - ''; - - installPhase = '' - mkdir -p $out/bin - - # create a symbolic link for the repository directory - ln -s ${repository} $out/repository - - install -Dm644 target/${pname}-${version}.jar $out/share/java - # create a wrapper that will automatically set the classpath - # this should be the paths from the dependency derivation - makeWrapper ${jre}/bin/java $out/bin/${pname} \ - --add-flags "-jar $out/share/java/${pname}-${version}.jar" - ''; -} -``` -::: {.note} -Our script produces a dependency on `jre` rather than `jdk` to restrict the runtime closure necessary to run the application. -::: - -This will give you an executable shell-script that launches your JAR with all the dependencies available. - -```bash -❯ tree $(nix-build --no-out-link runnable-jar.nix) -/nix/store/8d4c3ibw8ynsn01ibhyqmc1zhzz75s26-maven-demo-1.0 -├── bin -│   └── maven-demo -├── repository -> /nix/store/g87va52nkc8jzbmi1aqdcf2f109r4dvn-maven-repository -└── share - └── java - └── maven-demo-1.0.jar - -❯ $(nix-build --no-out-link --option tarball-ttl 1 runnable-jar.nix)/bin/maven-demo -NixOS 😀 is super cool 😃! -``` diff --git a/doc/redirects.json b/doc/redirects.json index dd0e844fbbeec..df5c7c9f42eae 100644 --- a/doc/redirects.json +++ b/doc/redirects.json @@ -3195,30 +3195,6 @@ "stable-maven-plugins": [ "index.html#stable-maven-plugins" ], - "maven-mvn2nix": [ - "index.html#maven-mvn2nix" - ], - "solving-for-dependencies": [ - "index.html#solving-for-dependencies" - ], - "buildmaven-with-nixosmvn2nix-maven-plugin": [ - "index.html#buildmaven-with-nixosmvn2nix-maven-plugin" - ], - "double-invocation": [ - "index.html#double-invocation" - ], - "building-a-jar": [ - "index.html#building-a-jar" - ], - "runnable-jar": [ - "index.html#runnable-jar" - ], - "classpath": [ - "index.html#classpath" - ], - "manifest-file-via-maven-plugin": [ - "index.html#manifest-file-via-maven-plugin" - ], "nim": [ "index.html#nim" ], diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index d55b5bfd42a7d..e7fd5375f2fea 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -35,6 +35,11 @@ [v1.7.0](https://github.com/jtroo/kanata/releases/tag/v1.7.0) for more information. +- The `maven.buildMaven` builder was removed. Instead, in-tree users should use + `maven.buildMavenPackage`, and out-of-tree user who want to continue + to use `mvn2nix` should see + [the upstream repository](https://github.com/fzakaria/mvn2nix). + - the notmuch vim plugin now lives in a separate output of the `notmuch` package. Installing `notmuch` will not bring the notmuch vim package anymore, add `vimPlugins.notmuch-vim` to your (Neo)vim configuration if you want the diff --git a/pkgs/by-name/ma/maven/build-maven.nix b/pkgs/by-name/ma/maven/build-maven.nix deleted file mode 100644 index 7ac8afdde225a..0000000000000 --- a/pkgs/by-name/ma/maven/build-maven.nix +++ /dev/null @@ -1,88 +0,0 @@ -{ stdenv, maven, runCommand, writeText, fetchurl, lib, requireFile, linkFarm }: -# Takes an info file generated by mvn2nix -# (https://github.com/NixOS/mvn2nix-maven-plugin) and builds the maven -# project with it. -# -# repo: A local maven repository with the project's dependencies. -# -# settings: A settings.xml to pass to maven to use the repo. -# -# build: A simple build derivation that uses mvn compile and package to build -# the project. -# -# @example -# project = pkgs.buildMaven ./project-info.json -infoFile: -let - info = lib.importJSON infoFile; - - dependencies = lib.flatten (map (dep: - let - inherit (dep) sha1 groupId artifactId version metadata repository-id; - versionDir = dep.unresolved-version or version; - authenticated = dep.authenticated or false; - url = dep.url or ""; - - fetch = if (url != "") then - ((if authenticated then requireFile else fetchurl) { - inherit url sha1; - }) - else - ""; - - fetchMetadata = (if authenticated then requireFile else fetchurl) { - inherit (metadata) url sha1; - }; - - layout = "${ - builtins.replaceStrings [ "." ] [ "/" ] groupId - }/${artifactId}/${versionDir}"; - in lib.optional (url != "") { - layout = "${layout}/${fetch.name}"; - drv = fetch; - } ++ lib.optionals (dep ? metadata) ([{ - layout = "${layout}/maven-metadata-${repository-id}.xml"; - drv = fetchMetadata; - }] ++ lib.optional (fetch != "") { - layout = "${layout}/${ - builtins.replaceStrings [ version ] [ dep.unresolved-version ] - fetch.name - }"; - drv = fetch; - })) info.dependencies); - - repo = linkFarm "maven-repository" (lib.forEach dependencies (dependency: { - name = dependency.layout; - path = dependency.drv; - })); - - settings = writeText "settings.xml" '' - - ${repo} - - ''; - - src = dirOf infoFile; -in { - inherit repo settings info; - - build = stdenv.mkDerivation { - name = "${info.project.artifactId}-${info.project.version}.jar"; - - src = builtins.filterSource (path: type: - (toString path) != (toString (src + "/target")) && (toString path) - != (toString (src + "/.git"))) src; - - buildInputs = [ maven ]; - - buildPhase = "mvn --offline --settings ${settings} compile"; - - installPhase = '' - mvn --offline --settings ${settings} package - mv target/*.jar $out - ''; - }; -} diff --git a/pkgs/by-name/ma/maven/package.nix b/pkgs/by-name/ma/maven/package.nix index f7d88548f36b0..589a2c042fb63 100644 --- a/pkgs/by-name/ma/maven/package.nix +++ b/pkgs/by-name/ma/maven/package.nix @@ -35,9 +35,7 @@ stdenvNoCC.mkDerivation (finalAttrs: { ''; passthru = { - buildMaven = callPackage ./build-maven.nix { - maven = finalAttrs.finalPackage; - }; + buildMaven = throw "mvn2nix support was removed from Nixpkgs; please use https://github.com/fzakaria/mvn2nix or maven.buildMavenPackage instead"; # Added 2024-11-23 buildMavenPackage = callPackage ./build-maven-package.nix { maven = finalAttrs.finalPackage; };