Merge pull request #297224 from WilliButz/repart-image/mkDerivation

nixos/repart-image: refactor to use mkDerivation instead of runCommand
This commit is contained in:
nikstur 2024-03-21 12:50:17 +01:00 committed by GitHub
commit 80f60ad1f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 85 additions and 42 deletions

View File

@ -2,8 +2,8 @@
# NixOS module that can be imported. # NixOS module that can be imported.
{ lib { lib
, stdenvNoCC
, runCommand , runCommand
, runCommandLocal
, python3 , python3
, black , black
, ruff , ruff
@ -26,15 +26,18 @@
, xz , xz
# arguments # arguments
, name
, version
, imageFileBasename , imageFileBasename
, compression , compression
, fileSystems , fileSystems
, partitions , partitionsJSON
, split , split
, seed , seed
, definitionsDirectory , definitionsDirectory
, sectorSize , sectorSize
, mkfsEnv ? {} , mkfsEnv ? {}
, createEmpty ? true
}: }:
let let
@ -52,11 +55,6 @@ let
mypy --strict $out mypy --strict $out
''; '';
amendedRepartDefinitions = runCommandLocal "amended-repart.d" {} ''
definitions=$(${amendRepartDefinitions} ${partitions} ${definitionsDirectory})
cp -r $definitions $out
'';
fileSystemToolMapping = { fileSystemToolMapping = {
"vfat" = [ dosfstools mtools ]; "vfat" = [ dosfstools mtools ];
"ext4" = [ e2fsprogs.bin ]; "ext4" = [ e2fsprogs.bin ];
@ -78,53 +76,88 @@ let
"xz" = "xz --keep --verbose --threads=0 -${toString compression.level}"; "xz" = "xz --keep --verbose --threads=0 -${toString compression.level}";
}."${compression.algorithm}"; }."${compression.algorithm}";
in in
stdenvNoCC.mkDerivation (finalAttrs:
runCommand imageFileBasename (if (version != null)
{ then { pname = name; inherit version; }
else { inherit name; }
) // {
__structuredAttrs = true; __structuredAttrs = true;
nativeBuildInputs = [ nativeBuildInputs = [
systemd systemd
fakeroot fakeroot
util-linux util-linux
] ++ lib.optionals (compression.enable) [
compressionPkg compressionPkg
] ++ fileSystemTools; ] ++ fileSystemTools;
env = mkfsEnv; env = mkfsEnv;
inherit partitionsJSON definitionsDirectory;
# relative path to the repart definitions that are read by systemd-repart
finalRepartDefinitions = "repart.d";
systemdRepartFlags = [ systemdRepartFlags = [
"--dry-run=no" "--dry-run=no"
"--empty=create"
"--size=auto" "--size=auto"
"--seed=${seed}" "--seed=${seed}"
"--definitions=${amendedRepartDefinitions}" "--definitions=${finalAttrs.finalRepartDefinitions}"
"--split=${lib.boolToString split}" "--split=${lib.boolToString split}"
"--json=pretty" "--json=pretty"
] ++ lib.optionals createEmpty [
"--empty=create"
] ++ lib.optionals (sectorSize != null) [ ] ++ lib.optionals (sectorSize != null) [
"--sector-size=${toString sectorSize}" "--sector-size=${toString sectorSize}"
]; ];
passthru = { dontUnpack = true;
inherit amendRepartDefinitions amendedRepartDefinitions; dontConfigure = true;
}; doCheck = false;
} ''
mkdir -p $out
cd $out
echo "Building image with systemd-repart..." patchPhase = ''
unshare --map-root-user fakeroot systemd-repart \ runHook prePatch
''${systemdRepartFlags[@]} \
${imageFileBasename}.raw \
| tee repart-output.json
amendedRepartDefinitionsDir=$(${amendRepartDefinitions} $partitionsJSON $definitionsDirectory)
ln -vs $amendedRepartDefinitionsDir $finalRepartDefinitions
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 # Compression is implemented in the same derivation as opposed to in a
# separate derivation to allow users to save disk space. Disk images are # 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. # 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 for f in ${imageFileBasename}*; do
echo "Compressing $f with ${compression.algorithm}..." echo "Compressing $f with ${compression.algorithm}..."
# Keep the original file when compressing and only delete it afterwards # Keep the original file when compressing and only delete it afterwards
${compressionCommand} $f && rm $f ${compressionCommand} $f && rm $f
done done
fi '' + ''
'' mv -v repart-output.json ${imageFileBasename}* $out
runHook postInstall
'';
passthru = {
inherit amendRepartDefinitions;
};
})

View File

@ -211,6 +211,15 @@ in
''; '';
}; };
finalPartitions = lib.mkOption {
type = lib.types.attrs;
internal = true;
readOnly = true;
description = lib.mdDoc ''
Convenience option to access partitions with added closures.
'';
};
}; };
config = { config = {
@ -224,6 +233,16 @@ in
"zstd" = ".zst"; "zstd" = ".zst";
"xz" = ".xz"; "xz" = ".xz";
}."${cfg.compression.algorithm}"; }."${cfg.compression.algorithm}";
makeClosure = paths: pkgs.closureInfo { rootPaths = paths; };
# Add the closure of the provided Nix store paths to cfg.partitions so
# that amend-repart-definitions.py can read it.
addClosure = _name: partitionConfig: partitionConfig // (
lib.optionalAttrs
(partitionConfig.storePaths or [ ] != [ ])
{ closure = "${makeClosure partitionConfig.storePaths}/store-paths"; }
);
in in
{ {
name = lib.mkIf (config.system.image.id != null) (lib.mkOptionDefault config.system.image.id); name = lib.mkIf (config.system.image.id != null) (lib.mkOptionDefault config.system.image.id);
@ -239,6 +258,8 @@ in
"xz" = 3; "xz" = 3;
}."${cfg.compression.algorithm}"; }."${cfg.compression.algorithm}";
}; };
finalPartitions = lib.mapAttrs addClosure cfg.partitions;
}; };
system.build.image = system.build.image =
@ -247,36 +268,25 @@ in
(f: f != null) (f: f != null)
(lib.mapAttrsToList (_n: v: v.repartConfig.Format or null) cfg.partitions); (lib.mapAttrsToList (_n: v: v.repartConfig.Format or null) cfg.partitions);
makeClosure = paths: pkgs.closureInfo { rootPaths = paths; };
# Add the closure of the provided Nix store paths to cfg.partitions so
# that amend-repart-definitions.py can read it.
addClosure = _name: partitionConfig: partitionConfig // (
lib.optionalAttrs
(partitionConfig.storePaths or [ ] != [ ])
{ closure = "${makeClosure partitionConfig.storePaths}/store-paths"; }
);
finalPartitions = lib.mapAttrs addClosure cfg.partitions;
format = pkgs.formats.ini { }; format = pkgs.formats.ini { };
definitionsDirectory = utils.systemdUtils.lib.definitions definitionsDirectory = utils.systemdUtils.lib.definitions
"repart.d" "repart.d"
format format
(lib.mapAttrs (_n: v: { Partition = v.repartConfig; }) finalPartitions); (lib.mapAttrs (_n: v: { Partition = v.repartConfig; }) cfg.finalPartitions);
partitions = pkgs.writeText "partitions.json" (builtins.toJSON finalPartitions); partitionsJSON = pkgs.writeText "partitions.json" (builtins.toJSON cfg.finalPartitions);
mkfsEnv = mkfsOptionsToEnv cfg.mkfsOptions; mkfsEnv = mkfsOptionsToEnv cfg.mkfsOptions;
in in
pkgs.callPackage ./repart-image.nix { pkgs.callPackage ./repart-image.nix {
systemd = cfg.package; systemd = cfg.package;
inherit (cfg) imageFileBasename compression split seed sectorSize; inherit (cfg) name version imageFileBasename compression split seed sectorSize;
inherit fileSystems definitionsDirectory partitions mkfsEnv; inherit fileSystems definitionsDirectory partitionsJSON mkfsEnv;
}; };
meta.maintainers = with lib.maintainers; [ nikstur ]; meta.maintainers = with lib.maintainers; [ nikstur willibutz ];
}; };
} }