nix: ensure pureness of the bootstrappedSrc derivation
Now, the hash should be pretty resilient against all changes that are not affected by ./bootstrap.
diff --git a/flake.nix b/flake.nix
index 18fc52ec..4c20c0ab 100644
--- a/flake.nix
+++ b/flake.nix
@@ -21,7 +21,8 @@
systems = nixpkgs.lib.systems.flakeExposed;
perSystem = { config, pkgs, ... }:
let
- limine = pkgs.callPackage ./nix/build.nix { };
+ keep-directory-diff = pkgs.callPackage ./nix/keep-directory-diff.nix { };
+ limine = pkgs.callPackage ./nix/build.nix { inherit keep-directory-diff; };
in
{
devShells = {
diff --git a/nix/build.nix b/nix/build.nix
index 813fe4b9..160a8261 100644
--- a/nix/build.nix
+++ b/nix/build.nix
@@ -14,6 +14,7 @@
# Helpers
fd
, lib
+, keep-directory-diff
, nix-gitignore
, stdenv
@@ -28,33 +29,42 @@
}:
let
+ # The actual current source but close to the repo state, i.e., no files from
+ # the bootstrap step.
currentRepoSrc = nix-gitignore.gitignoreSource [
# Additional git ignores:
"flake.nix" # otherwise
"flake.lock"
"nix/"
+
+ # bootstrapped sources from ./bootstrap
+ "/build-aux/freestanding-toolchain"
+ "/freestanding-headers"
+ "/decompressor/cc-runtime"
+ "/limine-efi"
+ "/tinf"
+ "/common/flanterm"
+ "/stb"
] ../.;
# Contains the sources downloaded by the Git submodule-like initialation done
# in ./bootstrap.
#
# ALWAYS update the hash when one of the network dependencies in ./bootstrap
- # changes. Also, before updating, it is recommended to run "make clean"
- # beforehand.
+ # changes.
# bootstrappedSrcHash = lib.fakeHash;
- #
- # TODO: Unfortunately, currently this hash changes for almost every repository
- # change. We need to strip down this derivation further to only contain the
- # changed sources.
- bootstrappedSrcHash = "sha256-UU5pkdbaKXPs/i/hnuk4vZcxiag1cTsTCcn2LGzPuMs=";
- bootstrappedSrc = stdenvNoCC.mkDerivation {
- pname = "limine-bootstrapped";
+ bootstrappedSrcHash = "sha256-uggy1cDftq0tPD777hS+rz2oBnP2Q2AQ9xHdM8QhBQQ=";
+
+ # The full accumulated source tree to build Limine from.
+ bootstrappedSrc = stdenv.mkDerivation {
+ pname = "limine-src-bootstrapped";
version = "0.0.0";
src = currentRepoSrc;
nativeBuildInputs = [
cacert
- git
fd
+ git
+ keep-directory-diff
];
buildPhase = ''
runHook preBuild
@@ -63,6 +73,8 @@ let
# steps apart from downloading sources.
AUTOMAKE=true AUTORECONF=true ./bootstrap
+ keep-directory-diff ${currentRepoSrc} .
+
# When cloning, Git automatically creates hooks. Unfortunately, in a Nix
# environment / on a NixOS system, this includes Nix store paths.
# However, me must prevent to have any Nix store path inside the final
diff --git a/nix/keep-directory-diff.nix b/nix/keep-directory-diff.nix
new file mode 100644
index 00000000..b03f797e
--- /dev/null
+++ b/nix/keep-directory-diff.nix
@@ -0,0 +1,55 @@
+{ ansi
+, argc
+, fd
+, lib
+, writeShellScriptBin
+}:
+
+writeShellScriptBin "keep-directory-diff" ''
+ # The following @-annotations belong to https://github.com/sigoden/argc
+ #
+ # @describe
+ # This script takes two directories. The first directory is the base source.
+ # The second is the base source plus potentially additional or modified
+ # sources. It removes all files from the second directory that are unchanged
+ # in the first directory. The use case is to get the actual difference that
+ # preparation scripts of a source tree cause, such as through downloading
+ # certain resources into the tree.
+ #
+ # Only file content is checked, not file attributes. Symlinks are ignored.
+ #
+ # @arg base! Base directory
+ # Path to source directory
+ # @arg target! Target directory
+ # Path to target directory. This directory is modified.
+
+ # Bash strict mode.
+ set -eou pipefail
+
+ export PATH="${lib.makeBinPath([
+ ansi
+ argc
+ fd
+ ])
+ }:$PATH"
+
+ # Do the "argc" magic. Reference: https://github.com/sigoden/argc
+ eval "$(argc --argc-eval "$0" "$@")"
+
+ # Find directories and regular files, don't follow symlinks.
+ readarray -d "" BASE_FILES < <(cd "$argc_base" && fd --unrestricted --print0 --type file)
+
+ for FILE in "''${BASE_FILES[@]}"; do
+ # Check if the content of the file was changed.
+ TARGET_FILE=$(realpath "$argc_target/$FILE" --relative-to=$PWD)
+ FILE=$(realpath "$argc_base/$FILE" --relative-to=$PWD)
+ echo -e "base file : $(ansi bold)$FILE$(ansi reset)"
+ echo -e "target file: $(ansi bold)$TARGET_FILE$(ansi reset)"
+ if cmp -s "$FILE" "$TARGET_FILE"; then
+ echo -e "Removing $(ansi bold)$TARGET_FILE$(ansi reset) as it hasn't changed."
+ rm -f "$TARGET_FILE"
+ else
+ echo -e "Keeping $(ansi bold)$TARGET_FILE$(ansi reset) as it was modified"
+ fi
+ done
+''
