nixpkgs/nixos/modules/image/repart-image.nix

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

164 lines
3.6 KiB
Nix
Raw Normal View History

# This is an expression meant to be called from `./repart.nix`, it is NOT a
# NixOS module that can be imported.
{ lib
, stdenvNoCC
, runCommand
, python3
, black
, ruff
, mypy
, systemd
, fakeroot
, util-linux
# filesystem tools
, dosfstools
, mtools
, e2fsprogs
, squashfsTools
, erofs-utils
, btrfs-progs
, xfsprogs
# compression tools
, zstd
, xz
# arguments
, name
, version
, imageFileBasename
, compression
, fileSystems
, partitionsJSON
, split
, seed
, definitionsDirectory
, sectorSize
, mkfsEnv ? {}
, createEmpty ? true
}:
let
amendRepartDefinitions = runCommand "amend-repart-definitions.py"
{
# TODO: ruff does not splice properly in nativeBuildInputs
depsBuildBuild = [ ruff ];
nativeBuildInputs = [ python3 black mypy ];
} ''
install ${./amend-repart-definitions.py} $out
patchShebangs --build $out
black --check --diff $out
ruff --line-length 88 $out
mypy --strict $out
'';
fileSystemToolMapping = {
"vfat" = [ dosfstools mtools ];
"ext4" = [ e2fsprogs.bin ];
"squashfs" = [ squashfsTools ];
"erofs" = [ erofs-utils ];
"btrfs" = [ btrfs-progs ];
"xfs" = [ xfsprogs ];
};
fileSystemTools = builtins.concatMap (f: fileSystemToolMapping."${f}") fileSystems;
compressionPkg = {
"zstd" = zstd;
"xz" = xz;
}."${compression.algorithm}";
compressionCommand = {
"zstd" = "zstd --no-progress --threads=0 -${toString compression.level}";
"xz" = "xz --keep --verbose --threads=0 -${toString compression.level}";
}."${compression.algorithm}";
in
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"
"--size=auto"
"--seed=${seed}"
"--definitions=${finalAttrs.finalRepartDefinitions}"
"--split=${lib.boolToString split}"
"--json=pretty"
] ++ lib.optionals createEmpty [
"--empty=create"
] ++ lib.optionals (sectorSize != null) [
"--sector-size=${toString sectorSize}"
];
dontUnpack = true;
dontConfigure = true;
doCheck = false;
patchPhase = ''
runHook prePatch
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
# 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.
+ 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
'' + ''
mv -v repart-output.json ${imageFileBasename}* $out
runHook postInstall
'';
passthru = {
inherit amendRepartDefinitions;
};
})