:: commit 98ab791492275fd18a404de72cd522d43ff3dd18

Philipp Schuster <philipp.schuster@cyberus-technology.de> — 2024-03-22 13:26

parents: d320199530

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
+''
tab: 248 wrap: offon