maven: add fixed point evaluation to buildMavenPackage

This allows calling `buildMavenPackage` with a function that receives a
`finalAttrs` parameter, much like `stdenv.mkDerivation(finalAttrs: ...)`
works.
This commit is contained in:
Benedikt Ritter
2026-04-30 14:17:46 +02:00
parent 7cbec3af13
commit b04351ae41
2 changed files with 143 additions and 133 deletions

View File

@@ -17,14 +17,14 @@ Consider the following package:
maven,
}:
maven.buildMavenPackage rec {
maven.buildMavenPackage (finalAttrs: {
pname = "jd-cli";
version = "1.2.1";
src = fetchFromGitHub {
owner = "intoolswetrust";
repo = "jd-cli";
tag = "jd-cli-${version}";
tag = "jd-cli-${finalAttrs.version}";
hash = "sha256-rRttA5H0A0c44loBzbKH7Waoted3IsOgxGCD2VM0U/Q=";
};
@@ -50,7 +50,7 @@ maven.buildMavenPackage rec {
license = lib.licenses.gpl3Plus;
maintainers = with lib.maintainers; [ majiir ];
};
}
})
```
This package calls `maven.buildMavenPackage` to do its work. The primary difference from `stdenv.mkDerivation` is the `mvnHash` variable, which is a hash of all of the Maven dependencies.
@@ -133,7 +133,7 @@ step 2 which will most probably fail the build. The `go-offline` plugin cannot
handle these so-called [dynamic dependencies](https://github.com/qaware/go-offline-maven-plugin?tab=readme-ov-file#dynamic-dependencies).
In that case you must add these dynamic dependencies manually with:
```nix
maven.buildMavenPackage rec {
maven.buildMavenPackage {
manualMvnArtifacts = [
# add dynamic test dependencies here
"org.apache.maven.surefire:surefire-junit-platform:3.1.2"

View File

@@ -6,149 +6,159 @@
maven,
writers,
}:
{
src,
sourceRoot ? null,
buildOffline ? false,
doCheck ? true,
prePatch ? null,
patches ? [ ],
postPatch ? null,
pname,
version,
mvnJdk ? jdk,
mvnHash ? "",
mvnFetchExtraArgs ? { },
mvnDepsParameters ? "",
manualMvnArtifacts ? [ ],
manualMvnSources ? [ ],
mvnParameters ? "",
...
}@args:
# originally extracted from dbeaver
# created to allow using maven packages in the same style as rust
let
mvnSkipTests = lib.optionalString (!doCheck) "-DskipTests";
writeProxySettings = writers.writePython3 "write-proxy-settings" { } ./maven-proxy.py;
fetchedMavenDeps = stdenv.mkDerivation (
buildMavenPackage =
{
pname = "maven-deps-${pname}";
inherit
src
sourceRoot
prePatch
patches
postPatch
version
;
src,
sourceRoot ? null,
buildOffline ? false,
doCheck ? true,
prePatch ? null,
patches ? [ ],
postPatch ? null,
pname,
version,
mvnJdk ? jdk,
mvnHash ? "",
mvnFetchExtraArgs ? { },
mvnDepsParameters ? "",
manualMvnArtifacts ? [ ],
manualMvnSources ? [ ],
mvnParameters ? "",
...
}@args:
nativeBuildInputs = [
maven
]
++ args.nativeBuildInputs or [ ];
# originally extracted from dbeaver
# created to allow using maven packages in the same style as rust
env = mvnFetchExtraArgs.env or { } // {
JAVA_HOME = mvnJdk;
};
let
mvnSkipTests = lib.optionalString (!doCheck) "-DskipTests";
impureEnvVars = lib.fetchers.proxyImpureEnvVars;
writeProxySettings = writers.writePython3 "write-proxy-settings" { } ./maven-proxy.py;
buildPhase = ''
runHook preBuild
fetchedMavenDeps = stdenv.mkDerivation (
{
pname = "maven-deps-${pname}";
inherit
src
sourceRoot
prePatch
patches
postPatch
version
;
MAVEN_EXTRA_ARGS="-B"
nativeBuildInputs = [
maven
]
++ args.nativeBuildInputs or [ ];
# handle proxy
if [[ -n "''${HTTP_PROXY-}" ]] || [[ -n "''${HTTPS_PROXY-}" ]] || [[ -n "''${NO_PROXY-}" ]];then
mvnSettingsFile="$(mktemp -d)/settings.xml"
${writeProxySettings} $mvnSettingsFile
MAVEN_EXTRA_ARGS="$MAVEN_EXTRA_ARGS -s=$mvnSettingsFile"
fi
env = mvnFetchExtraArgs.env or { } // {
JAVA_HOME = mvnJdk;
};
# handle cacert by populating a trust store on the fly
if [[ -n "''${NIX_SSL_CERT_FILE-}" ]] && [[ "''${NIX_SSL_CERT_FILE-}" != "/no-cert-file.crt" ]];then
echo "using ''${NIX_SSL_CERT_FILE-} as trust store"
${jre-generate-cacerts} ${lib.getBin jdk}/bin/keytool $NIX_SSL_CERT_FILE
impureEnvVars = lib.fetchers.proxyImpureEnvVars;
MAVEN_EXTRA_ARGS="$MAVEN_EXTRA_ARGS -Djavax.net.ssl.trustStore=cacerts -Djavax.net.ssl.trustStorePassword=changeit"
fi
''
+ lib.optionalString buildOffline ''
mvn $MAVEN_EXTRA_ARGS de.qaware.maven:go-offline-maven-plugin:1.2.8:resolve-dependencies -Dmaven.repo.local=$out/.m2 ${mvnDepsParameters}
buildPhase = ''
runHook preBuild
for artifactId in ${toString manualMvnArtifacts}
do
echo "downloading manual $artifactId"
mvn $MAVEN_EXTRA_ARGS dependency:get -Dartifact="$artifactId" -Dmaven.repo.local=$out/.m2
done
MAVEN_EXTRA_ARGS="-B"
for artifactId in ${toString manualMvnSources}
do
group=$(echo $artifactId | cut -d':' -f1)
artifact=$(echo $artifactId | cut -d':' -f2)
echo "downloading manual sources $artifactId"
mvn $MAVEN_EXTRA_ARGS dependency:sources -DincludeGroupIds="$group" -DincludeArtifactIds="$artifact" -Dmaven.repo.local=$out/.m2
done
''
+ lib.optionalString (!buildOffline) ''
mvn $MAVEN_EXTRA_ARGS package -Dmaven.repo.local=$out/.m2 ${mvnSkipTests} ${mvnParameters}
''
+ ''
runHook postBuild
'';
# handle proxy
if [[ -n "''${HTTP_PROXY-}" ]] || [[ -n "''${HTTPS_PROXY-}" ]] || [[ -n "''${NO_PROXY-}" ]];then
mvnSettingsFile="$(mktemp -d)/settings.xml"
${writeProxySettings} $mvnSettingsFile
MAVEN_EXTRA_ARGS="$MAVEN_EXTRA_ARGS -s=$mvnSettingsFile"
fi
# keep only *.{pom,jar,sha1,nbm} and delete all ephemeral files with lastModified timestamps inside
installPhase = ''
runHook preInstall
# handle cacert by populating a trust store on the fly
if [[ -n "''${NIX_SSL_CERT_FILE-}" ]] && [[ "''${NIX_SSL_CERT_FILE-}" != "/no-cert-file.crt" ]];then
echo "using ''${NIX_SSL_CERT_FILE-} as trust store"
${jre-generate-cacerts} ${lib.getBin jdk}/bin/keytool $NIX_SSL_CERT_FILE
find $out -type f \( \
-name \*.lastUpdated \
-o -name resolver-status.properties \
-o -name _remote.repositories \) \
-delete
MAVEN_EXTRA_ARGS="$MAVEN_EXTRA_ARGS -Djavax.net.ssl.trustStore=cacerts -Djavax.net.ssl.trustStorePassword=changeit"
fi
''
+ lib.optionalString buildOffline ''
mvn $MAVEN_EXTRA_ARGS de.qaware.maven:go-offline-maven-plugin:1.2.8:resolve-dependencies -Dmaven.repo.local=$out/.m2 ${mvnDepsParameters}
runHook postInstall
'';
for artifactId in ${toString manualMvnArtifacts}
do
echo "downloading manual $artifactId"
mvn $MAVEN_EXTRA_ARGS dependency:get -Dartifact="$artifactId" -Dmaven.repo.local=$out/.m2
done
# don't do any fixup
dontFixup = true;
outputHashAlgo = if mvnHash != "" then null else "sha256";
outputHashMode = "recursive";
outputHash = mvnHash;
}
// (removeAttrs mvnFetchExtraArgs [ "env" ])
);
for artifactId in ${toString manualMvnSources}
do
group=$(echo $artifactId | cut -d':' -f1)
artifact=$(echo $artifactId | cut -d':' -f2)
echo "downloading manual sources $artifactId"
mvn $MAVEN_EXTRA_ARGS dependency:sources -DincludeGroupIds="$group" -DincludeArtifactIds="$artifact" -Dmaven.repo.local=$out/.m2
done
''
+ lib.optionalString (!buildOffline) ''
mvn $MAVEN_EXTRA_ARGS package -Dmaven.repo.local=$out/.m2 ${mvnSkipTests} ${mvnParameters}
''
+ ''
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 \
-o -name resolver-status.properties \
-o -name _remote.repositories \) \
-delete
runHook postInstall
'';
# don't do any fixup
dontFixup = true;
outputHashAlgo = if mvnHash != "" then null else "sha256";
outputHashMode = "recursive";
outputHash = mvnHash;
}
// (removeAttrs mvnFetchExtraArgs [ "env" ])
);
in
stdenv.mkDerivation (
removeAttrs args [ "mvnFetchExtraArgs" ]
// {
inherit fetchedMavenDeps;
nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [
maven
];
env = args.env or { } // {
JAVA_HOME = mvnJdk;
};
buildPhase = ''
runHook preBuild
mvnDeps=$(cp -dpR ${fetchedMavenDeps}/.m2 ./ && chmod +w -R .m2 && pwd)
runHook afterDepsSetup
mvn package -o -nsu "-Dmaven.repo.local=$mvnDeps/.m2" ${mvnSkipTests} ${mvnParameters}
runHook postBuild
'';
meta = args.meta or { } // {
platforms = args.meta.platforms or maven.meta.platforms;
};
}
);
in
stdenv.mkDerivation (
removeAttrs args [ "mvnFetchExtraArgs" ]
// {
inherit fetchedMavenDeps;
nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [
maven
];
env = args.env or { } // {
JAVA_HOME = mvnJdk;
};
buildPhase = ''
runHook preBuild
mvnDeps=$(cp -dpR ${fetchedMavenDeps}/.m2 ./ && chmod +w -R .m2 && pwd)
runHook afterDepsSetup
mvn package -o -nsu "-Dmaven.repo.local=$mvnDeps/.m2" ${mvnSkipTests} ${mvnParameters}
runHook postBuild
'';
meta = args.meta or { } // {
platforms = args.meta.platforms or maven.meta.platforms;
};
}
)
fnOrAttrs:
if !lib.isFunction fnOrAttrs then
buildMavenPackage fnOrAttrs
else
let
finalAttrs = fnOrAttrs finalAttrs;
in
buildMavenPackage finalAttrs