Skip to content

Commit

Permalink
Create a Nix setup for reproducible builds
Browse files Browse the repository at this point in the history
  • Loading branch information
ibbem committed Nov 15, 2024
1 parent 28d661e commit a053ead
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 0 deletions.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name := "TrueDiffDetective"

ThisBuild / organization := "org.variantsync"
// The version is duplicated in `default.nix`.
ThisBuild / version := "0.1.0-SNAPSHOT"

ThisBuild / scalaVersion := "2.13.1"
Expand Down
57 changes: 57 additions & 0 deletions default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
system ? builtins.currentSystem,
pkgs ?
import (builtins.fetchTarball {
name = "sources";
url = "https://github.com/nixos/nixpkgs/archive/6832d0d99649db3d65a0e15fa51471537b2c56a6.tar.gz";
sha256 = "1ww2vrgn8xrznssbd05hdlr3d4br6wbjlqprys1al8ahxkyl5syi";
}) {
inherit system;
config = {};
modules = [];
},
lib ? pkgs.lib,
callPackage ? pkgs.callPackage,
symlinkJoin ? pkgs.symlinkJoin,
sbt ?
pkgs.sbt.override {
jre = pkgs.jdk17;
},
buildSbtPackage ?
callPackage (import ./nix/buildSbtPackage.nix) {
inherit sbt;
},
truediff ?
callPackage (import ./nix/truediff.nix) {
inherit buildSbtPackage;
},
DiffDetective ?
import (builtins.fetchTarball {
name = "DiffDetective";
url = "https://github.com/VariantSync/DiffDetective/archive/0e7d810ae5826c9866750f87c7dce4140ac37ed6.tar.gz";
sha256 = "1kz55bivvbxg9g027q3a3r0q52cd54ayr96ifx87a7icmv7wp1yg";
}) {
inherit system pkgs;
},
dependenciesHash ? "sha256-Cev6nPHyUQvxv7ftA8fxVC4NYwCRzC/Dy4I1nyl+/wc=",
}:
buildSbtPackage {
pname = "TrueDiffDetective";
# The version is duplicated in `build.sbt`.
version = "0.1.0-SNAPSHOT";
src = with lib.fileset;
toSource {
root = ./.;
fileset = gitTracked ./.;
};

mavenRepo = symlinkJoin {
name = "TrueDiffDetective-maven-dependencies";
paths = [
DiffDetective.maven
truediff.maven
];
};

inherit dependenciesHash;
}
141 changes: 141 additions & 0 deletions nix/buildSbtPackage.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
{
lib,
stdenvNoCC,
sbt,
maven,
}: {
pname,
version,
src,
dependenciesHash ? lib.fakeHash,
mavenRepo ? null,
}:
stdenvNoCC.mkDerivation {
inherit pname;
inherit version;
inherit src;

outputs = ["out" "maven"];

nativeBuildInputs = [
sbt
];

fetchedDependencies = stdenvNoCC.mkDerivation {
pname = "${pname}-dependencies";
inherit version;
inherit src;

nativeBuildInputs = [
sbt
maven
];

# According to the wisdom of the internet
# (multiple issues, stack overflow etc., who mentioned this command along the way, but there is no actually useful documentation what that command should do),
# `sbt update` should be enough to download all necessary dependencies to build offline.
# However, it doesn't. Hence, we have to also do a fake compilation.
# In order to actually cache all depencies [1] without build artifacts
# (this could cause annoying reproducibility bugs caused by previous build outputs),
# we only add an empty file such that `sbt` "builds" without complains.
#
# [1]: https://stackoverflow.com/questions/52355642/sbt-compile-compiler-bridge#comment107617368_52430243
buildPhase = ''
runHook preBuild
# Find source directories
source_directories=($(find . -path "*/src/main/scala"))
# Delete all files except `build.sbt` and the `project/` directory to keep
# dependency fetching independet of other source changes.
find . -mindepth 1 -maxdepth 1 -not \( -name "build.sbt" -o -name "project" \) -exec rm -r {} +
# Add an empty file into each source directory such that sbt actually
# downloads all necessary dependencies.
for source_directory in "''${source_directories[@]}"
do
mkdir -p "$source_directory"
touch "$source_directory/empty.scala"
done
mkdir cache
${
lib.optionalString (mavenRepo != null) ''
cp -L -r ${mavenRepo} cache/maven-repo
chmod u+w -R cache/maven-repo
''
}
# Download necessary dependencies and tell sbt to cache them in a `cache/`
# directory.
sbt -Dsbt.home=cache/sbt -Dsbt.boot.directory=cache/sbt-boot -Dsbt.coursier.home=cache/coursier -Dsbt.ivy.home=cache/ivy -Dmaven.repo.local=cache/maven-repo update compile
runHook postBuild
'';

installPhase = ''
runHook preInstall
cp -r cache "$out"
if [ -d "$out/maven-repo" ]
then
# Keep only *.{pom,jar,sha1,nbm} and delete all ephemeral files with lastModified timestamps inside.
find "$out/maven-repo" -type f \
\( -not \( -name "*.pom" -o -name "*.jar" -o -name "*.sha1" -o -name "*.nbm" \) \
-o -name "maven-metadata*" \) \
-delete
fi
if [ -d "$out/ivy" ]
then
# Delete unnecessary files with impurities (timestamps).
find "$out/ivy" \
-type f \
-name "ivydata*.properties" \
-delete
# Override all other timestamps with a fixed value.
find "$out/ivy" \
-type f \
-name "*.xml" \
-exec sed -i 's/publication="[[:digit:]]*"/publication="19700101000001"/' -- {} +
fi
runHook postInstall
'';

dontFixup = true;
outputHashAlgo = "sha256";
outputHashMode = "recursive";
outputHash = dependenciesHash;
};

buildPhase = ''
runHook preBuild
# sbt needs write access to the cache.
cp -r "$fetchedDependencies" cache
chmod u+w -R cache
sbt -Dsbt.home=cache/sbt -Dsbt.boot.directory=cache/sbt-boot -Dsbt.coursier.home=cache/coursier -Dsbt.ivy.home=cache/ivy -Dmaven.repo.local=cache/maven-repo compile test package publishM2
runHook postBuild
'';

installPhase = ''
runHook preInstall
mkdir -p "$out/share/jars"
find . -name cache -prune -o -name "*.jar" -exec cp -t "$out/share/jars" {} +
mv cache/maven-repo "$maven"
# Keep only *.{pom,jar,sha1,nbm} and delete all ephemeral files with lastModified timestamps inside.
find "$maven" -type f \
\( -not \( -name "*.pom" -o -name "*.jar" -o -name "*.sha1" -o -name "*.nbm" \) \
-o -name "maven-metadata*" \) \
-delete
runHook postInstall
'';
}
17 changes: 17 additions & 0 deletions nix/truediff.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
buildSbtPackage,
fetchFromGitLab,
}:
buildSbtPackage {
pname = "truediff";
version = "0.2.0-SNAPSHOT";
src = fetchFromGitLab {
domain = "gitlab.rlp.net";
owner = "plmz";
repo = "truediff";
rev = "e540bd251b9a0fa5ff019595577f7ac2abca74dc";
hash = "sha256-Tz7PlgMLakRhBxDZxHppjTWMQhP5f5bK8Ve9hILXUn0=";
};

dependenciesHash = "sha256-OUNhilRJN4isnNRUoHAXOs24FTm7JpdVcOiQL5fTCVw=";
}

0 comments on commit a053ead

Please sign in to comment.