1{ runCommand
2, lib
3, stdenv
4, storeDir ? builtins.storeDir
5, writeScript
6, singularity
7, writeClosure
8, bash
9, vmTools
10, gawk
11, util-linux
12, runtimeShell
13, e2fsprogs
14}:
15rec {
16 shellScript = name: text:
17 writeScript name ''
18 #!${runtimeShell}
19 set -e
20 ${text}
21 '';
22
23 mkLayer =
24 { name
25 , contents ? [ ]
26 # May be "apptainer" instead of "singularity"
27 , projectName ? (singularity.projectName or "singularity")
28 }:
29 runCommand "${projectName}-layer-${name}"
30 {
31 inherit contents;
32 } ''
33 mkdir $out
34 for f in $contents ; do
35 cp -ra $f $out/
36 done
37 '';
38
39 buildImage =
40 let
41 defaultSingularity = singularity;
42 in
43 { name
44 , contents ? [ ]
45 , diskSize ? 1024
46 , runScript ? "#!${stdenv.shell}\nexec /bin/sh"
47 , runAsRoot ? null
48 , memSize ? 512
49 , singularity ? defaultSingularity
50 }:
51 let
52 projectName = singularity.projectName or "singularity";
53 runAsRootFile = shellScript "run-as-root.sh" runAsRoot;
54 runScriptFile = shellScript "run-script.sh" runScript;
55 result = vmTools.runInLinuxVM (
56 runCommand "${projectName}-image-${name}.img"
57 {
58 buildInputs = [ singularity e2fsprogs util-linux gawk ];
59 layerClosure = writeClosure contents;
60 preVM = vmTools.createEmptyImage {
61 size = diskSize;
62 fullName = "${projectName}-run-disk";
63 };
64 inherit memSize;
65 }
66 ''
67 rm -rf $out
68 mkdir disk
69 mkfs -t ext3 -b 4096 /dev/${vmTools.hd}
70 mount /dev/${vmTools.hd} disk
71 mkdir -p disk/img
72 cd disk/img
73 mkdir proc sys dev
74
75 # Run root script
76 ${lib.optionalString (runAsRoot != null) ''
77 mkdir -p ./${storeDir}
78 mount --rbind ${storeDir} ./${storeDir}
79 unshare -imnpuf --mount-proc chroot ./ ${runAsRootFile}
80 umount -R ./${storeDir}
81 ''}
82
83 # Build /bin and copy across closure
84 mkdir -p bin ./${builtins.storeDir}
85 for f in $(cat $layerClosure) ; do
86 cp -ar $f ./$f
87 done
88
89 for c in ${toString contents} ; do
90 for f in $c/bin/* ; do
91 if [ ! -e bin/$(basename $f) ] ; then
92 ln -s $f bin/
93 fi
94 done
95 done
96
97 # Create runScript and link shell
98 if [ ! -e bin/sh ]; then
99 ln -s ${runtimeShell} bin/sh
100 fi
101 mkdir -p .${projectName}.d
102 ln -s ${runScriptFile} .${projectName}.d/runscript
103
104 # Fill out .${projectName}.d
105 mkdir -p .${projectName}.d/env
106 touch .${projectName}.d/env/94-appsbase.sh
107
108 cd ..
109 mkdir -p /var/lib/${projectName}/mnt/session
110 echo "root:x:0:0:System administrator:/root:/bin/sh" > /etc/passwd
111 echo > /etc/resolv.conf
112 TMPDIR=$(pwd -P) ${projectName} build $out ./img
113 '');
114
115 in
116 result;
117}