Home Explore Blog CI



nixpkgs

4th chunk of `doc/languages-frameworks/maven.section.md`
a75a7c80eac00aa366c14d55bac6b2762433bf86659b810400000001000010ca
        "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 <nixpkgs> { },
}:
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 = ''
    runHook preBuild

    mvn package -Dmaven.repo.local=$out

    runHook postBuild
  '';

  # keep only *.{pom,jar,sha1,nbm} and delete all ephemeral files with lastModified timestamps inside
  installPhase = ''
    runHook preInstall

    find $out -type f \
      -name \*.lastUpdated -or \
      -name resolver-status.properties -or \
      -name _remote.repositories \
      -delete

    runHook postInstall
  '';

  # 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`.

Title: buildMaven Output and Double Invocation for Maven Dependency Management
Summary
This passage describes the output of `buildMaven` command, providing a Maven repository as a symlink farm and a simple build derivation. It also discusses an alternative approach called "Double Invocation" to manage Maven dependencies, where the Maven repository is treated as a single source. This method involves an initial build to determine the repository content and then setting the correct `outputHash`. This method may cause unnecessary rebuilds due to output hash changes, especially when using SNAPSHOT dependencies or version ranges.