Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ buildGradleApplication {

For further examples, checkout the [examples directory](./examples)

All available parameters of `buildGradleApplication` are documented in the [source code](https://github.com/raphiz/buildGradleApplication/blob/main/buildGradleApplication/default.nix)
All available parameters of `buildGradleApplication` are documented in the [source code](https://github.com/raphiz/buildGradleApplication/blob/main/buildGradle/buildGradleApplication.nix)

For more control over the installation phase, you may use `buildGradleArtifact`, and extra arguments will be passed to mkDerivation, so you can tweak preBuild, postBuild, etc. You can use script `$linkToJars folder` from `buildPhase` or other phases in order to change every jar inside a folder with a link to nix store as an usual nix build would normally do.

## Rules

Expand Down Expand Up @@ -198,7 +200,7 @@ buildGradleApplication {

### Rule #5: Using the `application` Plugin

Currently, the focus of this tool is to package Gradle applications. In order to launch a java application, we need both an main class as an entry point and a runtime classpath. The latter must contain both third-party dependencies fetched from a maven repository and project local libraries generated from other projects within the same build.
The main focus of this tool is to package Gradle applications with `buildGradleApplication`. In order to launch a java application, we need both an main class as an entry point and a runtime classpath. The latter must contain both third-party dependencies fetched from a maven repository and project local libraries generated from other projects within the same build.

Gradle provides exactly that (a so called [Distribution](https://docs.gradle.org/current/userguide/distribution_plugin.html#distribution_plugin)) with the built in [`application` plugin](https://docs.gradle.org/current/userguide/application_plugin.html). The required configuration is quite reasonable:

Expand Down
71 changes: 71 additions & 0 deletions buildGradle/buildGradleApplication.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
pkgs,
lib,
stdenvNoCC,
writeShellScript,
makeWrapper,
mkM2Repository,
updateVerificationMetadata,
buildGradleArtifact,
}: {
pname,
version,
src,
meta ? {},
env ? {},
jdk ? pkgs.jdk,
gradle ? pkgs.gradle,
buildInputs ? [],
nativeBuildInputs ? [],
dependencyFilter ? depSpec: true,
repositories ? ["https://plugins.gradle.org/m2/" "https://repo1.maven.org/maven2/"],
verificationFile ? "gradle/verification-metadata.xml",
buildTask ? ":installDist",
installLocation ? "build/install/*/",
...
}@params:
buildGradleArtifact ({

installPhase = ''
runHook preInstall
directories=( $(shopt -s nullglob; echo ${installLocation}) )

if [ ''${#directories[@]} -eq 0 ]; then
echo "Error: The built gradle application could not be found at ${installLocation}.
Most likely the option 'installLocation' is not set correctly.
The default value for 'installLocation' only works when the application plugin is applied on the root project itself.
If you applied it on a sub-project, adapt 'installLocation' accordingly, for example 'installLocation = \"path/to/sub-project/build/install/*/\"'." 1>&2;
exit 1
elif [ ''${#directories[@]} -gt 1 ]; then
echo "Error: The built gradle application could not be found at ${installLocation} because there are multiple matching directories (''${directories[@]})
Please adapt 'installLocation' to be more specific, for example by removing any wildcards." 1>&2;
exit 1
fi

pushd ${installLocation}

mkdir -p $out/lib/
mv lib/*.jar $out/lib/
$linkToJars $out/lib/

if [ -d agent-libs/ ]; then
mkdir -p $out/agent-libs/
mv agent-libs/*.jar $out/agent-libs/
$linkToJars} $out/agent-libs/
fi

mkdir -p $out/bin

cp $(ls bin/* | grep -v ".bat") $out/bin/${pname}

popd
runHook postInstall
'';

dontWrapGApps = true;
postFixup = ''
wrapProgram $out/bin/${pname} \
--set-default JAVA_HOME "${jdk.home}" \
''${gappsWrapperArgs[@]}
'';
} // params)
Original file line number Diff line number Diff line change
Expand Up @@ -20,47 +20,15 @@
repositories ? ["https://plugins.gradle.org/m2/" "https://repo1.maven.org/maven2/"],
verificationFile ? "gradle/verification-metadata.xml",
buildTask ? ":installDist",
installLocation ? "build/install/*/",
}: let
installPhase ? null,
...
}@params: let
m2Repository = mkM2Repository {
inherit pname version src dependencyFilter repositories verificationFile;
};

# Prepare a script that will replace that jars with references into the NIX store.
linkScript = writeShellScript "link-to-jars" ''
declare -A fileByName
declare -A hashByName
${
lib.concatMapStringsSep "\n"
(dep: "fileByName[\"${dep.name}\"]=\"${builtins.toString dep.jar}\"\nhashByName[\"${dep.name}\"]=\"${builtins.toString dep.hash}\"")
(builtins.filter (dep: (lib.strings.hasSuffix ".jar" dep.name && !lib.strings.hasSuffix "-javadoc.jar" dep.name && !lib.strings.hasSuffix "-sources.jar" dep.name)) m2Repository.dependencies)
}

for jar in "$1"/*.jar; do
dep=''${fileByName[$(basename "$jar")]}
if [[ -n "$dep" ]]; then
jarHash=$(sha256sum "$jar" | cut -c -64)
sriHash=''${hashByName[$(basename "$jar")]}
if [[ $sriHash == sha256-* ]]; then
referenceHash="$(echo ''${sriHash#sha256-} | base64 -d | ${pkgs.hexdump}/bin/hexdump -v -e '/1 "%02x"')"
else
referenceHash=$(sha256sum "$dep" | cut -c -64)
fi

if [[ "$referenceHash" == "$jarHash" ]]; then
echo "Replacing $jar with nix store reference $dep"
rm "$jar"
ln -s "$dep" "$jar"
else
echo "Hash of $jar differs from expected store reference $dep"
fi
else
echo "No linking candidate found for $jar"
fi
done
'';

package = stdenvNoCC.mkDerivation {
in
stdenvNoCC.mkDerivation ({
inherit pname version src buildInputs env;
meta =
{
Expand Down Expand Up @@ -95,49 +63,44 @@
runHook postBuild
'';

installPhase = ''
runHook preInstall
directories=( $(shopt -s nullglob; echo ${installLocation}) )

if [ ''${#directories[@]} -eq 0 ]; then
echo "Error: The built gradle application could not be found at ${installLocation}.
Most likely the option 'installLocation' is not set correctly.
The default value for 'installLocation' only works when the application plugin is applied on the root project itself.
If you applied it on a sub-project, adapt 'installLocation' accordingly, for example 'installLocation = \"path/to/sub-project/build/install/*/\"'." 1>&2;
exit 1
elif [ ''${#directories[@]} -gt 1 ]; then
echo "Error: The built gradle application could not be found at ${installLocation} because there are multiple matching directories (''${directories[@]})
Please adapt 'installLocation' to be more specific, for example by removing any wildcards." 1>&2;
exit 1
fi

pushd ${installLocation}
linkToJars = writeShellScript "link-to-jars" ''
declare -A fileByName
declare -A hashByName
${
lib.concatMapStringsSep "\n"
(dep: "fileByName[\"${dep.name}\"]=\"${builtins.toString dep.jar}\"\nhashByName[\"${dep.name}\"]=\"${builtins.toString dep.hash}\"")
(builtins.filter (dep: (lib.strings.hasSuffix ".jar" dep.name && !lib.strings.hasSuffix "-javadoc.jar" dep.name && !lib.strings.hasSuffix "-sources.jar" dep.name)) m2Repository.dependencies)
}

mkdir -p $out/lib/
mv lib/*.jar $out/lib/
echo ${linkScript} $out/lib/
${linkScript} $out/lib/
for jar in "$1"/*.jar; do
dep=''${fileByName[$(basename "$jar")]}
if [[ -n "$dep" ]]; then
jarHash=$(sha256sum "$jar" | cut -c -64)
sriHash=''${hashByName[$(basename "$jar")]}
if [[ $sriHash == sha256-* ]]; then
referenceHash="$(echo ''${sriHash#sha256-} | base64 -d | ${pkgs.hexdump}/bin/hexdump -v -e '/1 "%02x"')"
else
referenceHash=$(sha256sum "$dep" | cut -c -64)
fi

if [ -d agent-libs/ ]; then
mkdir -p $out/agent-libs/
mv agent-libs/*.jar $out/agent-libs/
${linkScript} $out/agent-libs/
if [[ "$referenceHash" == "$jarHash" ]]; then
echo "Replacing $jar with nix store reference $dep"
rm "$jar"
ln -s "$dep" "$jar"
else
echo "Hash of $jar differs from expected store reference $dep"
fi
else
echo "No linking candidate found for $jar"
fi
done
'';

mkdir -p $out/bin

cp $(ls bin/* | grep -v ".bat") $out/bin/${pname}

popd
runHook postInstall
'';

dontWrapGApps = true;
postFixup = ''
wrapProgram $out/bin/${pname} \
--set-default JAVA_HOME "${jdk.home}" \
''${gappsWrapperArgs[@]}
installPhase = ''
# Default build phase for buildGradleArtifact
echo 'buildGradleArtifact should specify an installPhase'
echo 'You can call $linkToJars} in order to replace jar files inside the parameter folder'
echo 'with links to nix store'
exit 1
'';
};
in
package
} // params)
File renamed without changes.
File renamed without changes.
16 changes: 9 additions & 7 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
overlays = {
default = final: prev: {
fetchArtifact = prev.callPackage ./fetchArtefact/default.nix {};
mkM2Repository = prev.callPackage ./buildGradleApplication/mkM2Repository.nix {};
buildGradleApplication = prev.callPackage ./buildGradleApplication/default.nix {};
mkM2Repository = prev.callPackage ./buildGradle/mkM2Repository.nix {};
buildGradleArtifact = prev.callPackage ./buildGradle/buildGradleArtifact.nix {};
buildGradleApplication = prev.callPackage ./buildGradle/buildGradleApplication.nix {};
updateVerificationMetadata = prev.callPackage ./update-verification-metadata/default.nix {};
gradleFromWrapper = import ./gradleFromWrapper final;
};
Expand All @@ -43,18 +44,19 @@
pkgs = nixpkgs.legacyPackages.${system};
in {
formatter = pkgs.alejandra;
legacyPackages = let
legacyPackages = rec {
fetchArtifact = pkgs.callPackage ./fetchArtefact/default.nix {};
mkM2Repository = pkgs.callPackage ./buildGradleApplication/mkM2Repository.nix {
mkM2Repository = pkgs.callPackage ./buildGradle/mkM2Repository.nix {
inherit fetchArtifact;
};
updateVerificationMetadata = pkgs.callPackage ./update-verification-metadata/default.nix {};
buildGradleApplication = pkgs.callPackage ./buildGradleApplication/default.nix {
buildGradleArtifact = pkgs.callPackage ./buildGradle/buildGradleArtifact.nix {
inherit mkM2Repository updateVerificationMetadata;
};
buildGradleApplication = pkgs.callPackage ./buildGradle/buildGradleApplication.nix {
inherit mkM2Repository updateVerificationMetadata buildGradleArtifact;
};
gradleFromWrapper = import ./gradleFromWrapper pkgs;
in {
inherit fetchArtifact mkM2Repository buildGradleApplication updateVerificationMetadata gradleFromWrapper;
};
};
};
Expand Down