{ config, lib, options, pkgs, ... }: { options = let vmVariantOptions = { virtualisation = { runAsRoot = lib.mkOption { type = lib.types.bool; default = false; }; sharedHostKeys = lib.mkOption { type = lib.types.bool; default = false; }; qemu.runInBackground = lib.mkOption { type = lib.types.bool; default = false; }; }; }; in { virtualisation = { vmVariant = vmVariantOptions; vmVariantWithBootLoader = vmVariantOptions; }; }; config = { virtualisation = let extendVMConfig = vmVariant: { boot.loader.efi.efiSysMountPoint = lib.mkVMOverride "/boot"; virtualisation = { runAsRoot = lib.mkIf vmVariant.virtualisation.sharedHostKeys true; sharedDirectories = lib.optionalAttrs (vmVariant.virtualisation.sharedHostKeys) { hostKeys = let path = "/etc/ssh"; in { source = path; target = path; }; }; }; }; virtualisation = config.virtualisation; in { vmVariant = extendVMConfig virtualisation.vmVariant; vmVariantWithBootLoader = extendVMConfig virtualisation.vmVariantWithBootLoader; }; # Replace native `qemu` with `remote-viewer` system.build = { vm = let packageName = "custom-nixos-vm"; mergedSystem = with options.system; lib.mergeDefinitions build.loc build.type (lib.lists.forEach ( builtins.filter (item: !(lib.path.hasPrefix ./. (/. + item.file))) build.definitionsWithLocations) (item: { inherit (item) file value; })); in lib.mkForce ( with { inherit (mergedSystem.mergedValue) vm; }; if (vm.name == packageName) then vm else let prefix = lib.concatStringsSep " " ( lib.optionals config.virtualisation.runAsRoot ( ["sudo"] ++ lib.optional config.virtualisation.qemu.runInBackground "-b")); suffix = lib.concatStringsSep " " ( lib.optional (!config.virtualisation.runAsRoot && config.virtualisation.qemu.runInBackground) "&"); wrapped = pkgs.writeShellApplication { name = "run-${config.system.name}-vm"; text = '' ${prefix} ${vm}/bin/run-${config.system.name}-vm ${suffix} ''; }; in # Rename package to `nixos-vm` pkgs.symlinkJoin { name = packageName; paths = [ wrapped ]; }); }; }; }