about summary refs log tree commit diff
path: root/nixos/modules/image
diff options
context:
space:
mode:
authorWilliButz <willibutz@posteo.de>2024-03-19 17:04:47 +0100
committerWilliButz <willibutz@posteo.de>2024-03-21 11:37:43 +0100
commitd7ef2defdadd066beaa81c82206dc23217402ef6 (patch)
treeb7faede99e1a87f2a59154648334473ace166524 /nixos/modules/image
parent1357b820aac78044f911e2638cf1ba40fff8d230 (diff)
nixos/repart-image: refactor to use mkDerivation
As a follow-up to https://github.com/NixOS/nixpkgs/pull/294096 this
should further improve the flexibility around building OS images with
systemd-repart:

* Previously the attribute set `compression` needed to be fully
  populated, including `algorithm` and `level` because
  `compression.enable` was evaluated by bash, after being interpolated
  as strings into the `buildCommand`. Now it's sufficient to pass
  `compression.enable = false` to the builder, e.g. in `overrideAttrs`,
  to disable the compression.
* Using mkDerivation allows for much more customization than the
  previously used `runCommand`, making use of phases and pre/post hooks.
  This is especially helpful for building multiple images from the same
  system configuration, e.g. to build an image `Y` based on a partially
  built raw image `X`,  by injecting a UKI that depends on `X` into a
  defered ESP.
* Before this change it was non-trivial to conduct further manipulations
  on the amended repart definitions. Now, the definitions that
  systemd-repart uses to build the image can be easily manipulated in
  `postPatch` or `preBuild`.

Aside from this, the build is now executed in the build directory, rather
than `$out`. This allows references to relative paths in the build
environment to be used, especially for `--definitions`, which previously
required an absolute path.
Diffstat (limited to 'nixos/modules/image')
-rw-r--r--nixos/modules/image/repart-image.nix85
-rw-r--r--nixos/modules/image/repart.nix6
2 files changed, 62 insertions, 29 deletions
diff --git a/nixos/modules/image/repart-image.nix b/nixos/modules/image/repart-image.nix
index 5ae523c43f589..83e766268cf04 100644
--- a/nixos/modules/image/repart-image.nix
+++ b/nixos/modules/image/repart-image.nix
@@ -2,8 +2,8 @@
 # NixOS module that can be imported.
 
 { lib
+, stdenvNoCC
 , runCommand
-, runCommandLocal
 , python3
 , black
 , ruff
@@ -26,15 +26,18 @@
 , xz
 
   # arguments
+, name
+, version
 , imageFileBasename
 , compression
 , fileSystems
-, partitions
+, partitionsJSON
 , split
 , seed
 , definitionsDirectory
 , sectorSize
 , mkfsEnv ? {}
+, createEmpty ? true
 }:
 
 let
@@ -52,11 +55,6 @@ let
     mypy --strict $out
   '';
 
-  amendedRepartDefinitions = runCommandLocal "amended-repart.d" {} ''
-    definitions=$(${amendRepartDefinitions} ${partitions} ${definitionsDirectory})
-    cp -r $definitions $out
-  '';
-
   fileSystemToolMapping = {
     "vfat" = [ dosfstools mtools ];
     "ext4" = [ e2fsprogs.bin ];
@@ -78,53 +76,88 @@ let
     "xz" = "xz --keep --verbose --threads=0 -${toString compression.level}";
   }."${compression.algorithm}";
 in
-
-runCommand imageFileBasename
-{
+  stdenvNoCC.mkDerivation (finalAttrs:
+  (if (version != null)
+  then { pname = name; inherit version; }
+  else { inherit name;  }
+  ) // {
   __structuredAttrs = true;
 
   nativeBuildInputs = [
     systemd
     fakeroot
     util-linux
+  ] ++ lib.optionals (compression.enable) [
     compressionPkg
   ] ++ fileSystemTools;
 
   env = mkfsEnv;
 
+  inherit partitionsJSON definitionsDirectory;
+
+  # relative path to the repart definitions that are read by systemd-repart
+  finalRepartDefinitions = "repart.d";
+
   systemdRepartFlags = [
     "--dry-run=no"
-    "--empty=create"
     "--size=auto"
     "--seed=${seed}"
-    "--definitions=${amendedRepartDefinitions}"
+    "--definitions=${finalAttrs.finalRepartDefinitions}"
     "--split=${lib.boolToString split}"
     "--json=pretty"
+  ] ++ lib.optionals createEmpty [
+    "--empty=create"
   ] ++ lib.optionals (sectorSize != null) [
     "--sector-size=${toString sectorSize}"
   ];
 
-  passthru = {
-    inherit amendRepartDefinitions amendedRepartDefinitions;
-  };
-} ''
-  mkdir -p $out
-  cd $out
+  dontUnpack = true;
+  dontConfigure = true;
+  doCheck = false;
+
+  patchPhase = ''
+    runHook prePatch
+
+    amendedRepartDefinitionsDir=$(${amendRepartDefinitions} $partitionsJSON $definitionsDirectory)
+    ln -vs $amendedRepartDefinitionsDir $finalRepartDefinitions
 
-  echo "Building image with systemd-repart..."
-  unshare --map-root-user fakeroot systemd-repart \
-    ''${systemdRepartFlags[@]} \
-    ${imageFileBasename}.raw \
-    | tee repart-output.json
+    runHook postPatch
+  '';
+
+  buildPhase = ''
+    runHook preBuild
+
+    echo "Building image with systemd-repart..."
+    unshare --map-root-user fakeroot systemd-repart \
+      ''${systemdRepartFlags[@]} \
+      ${imageFileBasename}.raw \
+      | tee repart-output.json
+
+    runHook postBuild
+  '';
+
+  installPhase = ''
+    runHook preInstall
 
+    mkdir -p $out
+  ''
   # Compression is implemented in the same derivation as opposed to in a
   # separate derivation to allow users to save disk space. Disk images are
   # already very space intensive so we want to allow users to mitigate this.
-  if ${lib.boolToString compression.enable}; then
+  + lib.optionalString compression.enable
+  ''
     for f in ${imageFileBasename}*; do
       echo "Compressing $f with ${compression.algorithm}..."
       # Keep the original file when compressing and only delete it afterwards
       ${compressionCommand} $f && rm $f
     done
-  fi
-''
+  '' + ''
+    mv -v repart-output.json ${imageFileBasename}* $out
+
+    runHook postInstall
+  '';
+
+  passthru = {
+    inherit amendRepartDefinitions;
+  };
+})
diff --git a/nixos/modules/image/repart.nix b/nixos/modules/image/repart.nix
index 90c9c7e51dfa3..aa5426cef0765 100644
--- a/nixos/modules/image/repart.nix
+++ b/nixos/modules/image/repart.nix
@@ -266,14 +266,14 @@ in
           format
           (lib.mapAttrs (_n: v: { Partition = v.repartConfig; }) finalPartitions);
 
-        partitions = pkgs.writeText "partitions.json" (builtins.toJSON finalPartitions);
+        partitionsJSON = pkgs.writeText "partitions.json" (builtins.toJSON finalPartitions);
 
         mkfsEnv = mkfsOptionsToEnv cfg.mkfsOptions;
       in
       pkgs.callPackage ./repart-image.nix {
         systemd = cfg.package;
-        inherit (cfg) imageFileBasename compression split seed sectorSize;
-        inherit fileSystems definitionsDirectory partitions mkfsEnv;
+        inherit (cfg) name version imageFileBasename compression split seed sectorSize;
+        inherit fileSystems definitionsDirectory partitionsJSON mkfsEnv;
       };
 
     meta.maintainers = with lib.maintainers; [ nikstur ];