1# Builds an btrfs image containing a populated /nix/store with the closure
2# of store paths passed in the storePaths parameter, in addition to the
3# contents of a directory that can be populated with commands. The
4# generated image is sized to only fit its contents, with the expectation
5# that a script resizes the filesystem at boot time.
6{
7 pkgs,
8 lib,
9 # List of derivations to be included
10 storePaths,
11 # Whether or not to compress the resulting image with zstd
12 compressImage ? false,
13 zstd,
14 # Shell commands to populate the ./files directory.
15 # All files in that directory are copied to the root of the FS.
16 populateImageCommands ? "",
17 volumeLabel,
18 uuid ? "44444444-4444-4444-8888-888888888888",
19 btrfs-progs,
20 libfaketime,
21 fakeroot,
22}:
23
24let
25 sdClosureInfo = pkgs.buildPackages.closureInfo { rootPaths = storePaths; };
26in
27pkgs.stdenv.mkDerivation {
28 name = "btrfs-fs.img${lib.optionalString compressImage ".zst"}";
29
30 nativeBuildInputs = [
31 btrfs-progs
32 libfaketime
33 fakeroot
34 ]
35 ++ lib.optional compressImage zstd;
36
37 buildCommand = ''
38 ${if compressImage then "img=temp.img" else "img=$out"}
39
40 set -x
41 (
42 mkdir -p ./files
43 ${populateImageCommands}
44 )
45
46 mkdir -p ./rootImage/nix/store
47
48 xargs -I % cp -a --reflink=auto % -t ./rootImage/nix/store/ < ${sdClosureInfo}/store-paths
49 (
50 GLOBIGNORE=".:.."
51 shopt -u dotglob
52
53 for f in ./files/*; do
54 cp -a --reflink=auto -t ./rootImage/ "$f"
55 done
56 )
57
58 cp ${sdClosureInfo}/registration ./rootImage/nix-path-registration
59
60 touch $img
61 faketime -f "1970-01-01 00:00:01" fakeroot mkfs.btrfs -L ${volumeLabel} -U ${uuid} -r ./rootImage --shrink $img
62
63 if ! btrfs check $img; then
64 echo "--- 'btrfs check' failed for BTRFS image ---"
65 return 1
66 fi
67
68 if [ ${builtins.toString compressImage} ]; then
69 echo "Compressing image"
70 zstd -v --no-progress ./$img -o $out
71 fi
72 '';
73}