diff options
-rw-r--r-- | modules/core/lazy-packages.nix | 67 | ||||
-rw-r--r-- | modules/module-list.nix | 1 | ||||
-rw-r--r-- | release.nix | 15 |
3 files changed, 81 insertions, 2 deletions
diff --git a/modules/core/lazy-packages.nix b/modules/core/lazy-packages.nix new file mode 100644 index 00000000..939ece52 --- /dev/null +++ b/modules/core/lazy-packages.nix @@ -0,0 +1,67 @@ +{ config, pkgs, lib, ... }: + +let + inherit (lib) escapeShellArg; + inherit (config.vuizvui) lazyPackages; + + # Encode the store path in base 64 so that the wrapper + # doesn't have a direct dependency on the package. + encoder = "${escapeShellArg "${pkgs.coreutils}/bin/base64"} -w0"; + decoder = "${escapeShellArg "${pkgs.coreutils}/bin/base64"} -d"; + + # The command used to fetch the store path from the binary cache. + fetchSubstitute = "${escapeShellArg "${pkgs.nix}/bin/nix-store"} -r"; + + mkWrapper = package: pkgs.runCommand "${package.name}-lazy" { + inherit package; + } '' + encoded="$(echo "$package" | ${encoder})" + + if [ ! -e "$package/bin" ]; then + echo "Store path $package doesn't have a \`bin' directory" \ + "so we can't create lazy wrappers for it. Please" \ + "remove \`${escapeShellArg package.name}' from" \ + "\`vuizvui.lazyPackages'." >&2 + exit 1 + fi + + for bin in "$package"/bin/*; do + [ -x "$bin" -a ! -d "$bin" ] || continue + binpath="''${bin#$package/}" + + mkdir -p "$out/bin" + ( echo ${escapeShellArg "#!${pkgs.stdenv.shell}"} + echo "encoded='$encoded'" + echo "binpath='$binpath'" + echo -n ${escapeShellArg '' + storepath="$(echo "$encoded" | ${decoder})" + program="$storepath/$binpath" + if [ ! -e "$storepath" ]; then + ${fetchSubstitute} "$storepath" || exit $? + fi + exec "$program" "$@" + ''} + ) > "$out/bin/$(basename "$bin")" + chmod +x "$out/bin/$(basename "$bin")" + done + ''; + + wrappers = map mkWrapper config.vuizvui.lazyPackages; + +in { + options.vuizvui.lazyPackages = lib.mkOption { + type = lib.types.listOf lib.types.package; + default = []; + example = lib.literalExample "[ pkgs.gimp pkgs.libreoffice ]"; + description = '' + Packages which are built for this system but instead of being a full + runtime dependency, only wrappers of all executables that reside in the + <literal>bin</literal> directory are actually runtime dependencies. + + As soon as one of these wrappers is executed, the real package is fetched + and the corresponding binary is executed. + ''; + }; + + config.environment.systemPackages = map mkWrapper lazyPackages; +} diff --git a/modules/module-list.nix b/modules/module-list.nix index b12d1fff..5994dd61 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -2,6 +2,7 @@ ./core/common.nix ./core/licensing.nix ./core/tests.nix + ./core/lazy-packages.nix ./hardware/gamecontroller.nix ./hardware/rtl8192cu ./hardware/t100ha diff --git a/release.nix b/release.nix index 5591dcac..b71ad0c3 100644 --- a/release.nix +++ b/release.nix @@ -69,8 +69,19 @@ let in with pkgsUpstream.lib; with builtins; { machines = let - getBuild = const (getAttr "build"); - in mapAttrsRecursiveCond (m: !(m ? eval)) getBuild allMachines; + # We need to expose all the real builds within vuizvui.lazyPackages to make + # sure they don't get garbage collected on the Hydra instance. + wrapLazy = machine: pkgsUpstream.runCommand machine.build.name { + fakeRuntimeDeps = machine.eval.config.vuizvui.lazyPackages; + product = machine.build; + } '' + mkdir -p "$out/nix-support" + echo "$product" > "$out/nix-support/fake-runtime-dependencies" + for i in $fakeRuntimeDeps; do + echo "$i" >> "$out/nix-support/fake-runtime-dependencies" + done + ''; + in mapAttrsRecursiveCond (m: !(m ? eval)) (const wrapLazy) allMachines; isoImages = let buildIso = attrs: let |