{ description = "vmix — composable QEMU VM image building and orchestration"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; }; outputs = { self, nixpkgs, ... }: let system = "x86_64-linux"; pkgs = import nixpkgs { inherit system; config.allowUnfree = true; }; lib = pkgs.lib; vmixLib = import ./lib { inherit pkgs lib system; }; in { overlays.default = import ./overlay.nix; nixosModules.default = import ./module.nix; lib.${system} = vmixLib; packages.${system} = { toDisk = pkgs.writeShellScriptBin "vmix-to-disk" '' set -euo pipefail usage() { echo "Usage: vmix-to-disk " echo "" echo "Write a vmix qcow2 image to a physical disk and expand the Windows partition." echo "" echo "Examples:" echo " vmix-to-disk /nix/store/...-win10-ltsc-vmix.qcow2 /dev/sda" echo " vmix-to-disk ./my-image.qcow2 /dev/nvme0n1" exit 1 } [[ ''${#} -ne 2 ]] && usage IMAGE="$1" DISK="$2" [[ $EUID -ne 0 ]] && { echo "Error: must run as root"; exit 1; } [[ ! -f "$IMAGE" ]] && { echo "Error: image not found: $IMAGE"; exit 1; } [[ ! -b "$DISK" ]] && { echo "Error: not a block device: $DISK"; exit 1; } if ${pkgs.util-linux}/bin/mount | grep -q "^''${DISK}"; then echo "Error: $DISK has mounted partitions — unmount first" exit 1 fi DISK_SIZE=$(${pkgs.util-linux}/bin/blockdev --getsize64 "$DISK") DISK_SIZE_GB=$(( DISK_SIZE / 1024 / 1024 / 1024 )) echo "=== vmix to physical disk ===" echo "Image: $IMAGE" echo "Target: $DISK ($DISK_SIZE_GB GB)" echo "" echo "WARNING: This will DESTROY all data on $DISK" read -rp "Continue? [y/N] " confirm [[ "$confirm" != "y" && "$confirm" != "Y" ]] && { echo "Aborted."; exit 0; } echo "" echo "[1/4] Writing image to disk..." ${pkgs.qemu}/bin/qemu-img convert -p -f qcow2 -O raw "$IMAGE" "$DISK" echo "[2/4] Fixing GPT backup header..." ${pkgs.gptfdisk}/bin/sgdisk -e "$DISK" echo "[3/4] Expanding Windows partition (partition 3) to fill disk..." ${pkgs.parted}/bin/parted -s "$DISK" resizepart 3 100% # detect partition device name (nvme/mmcblk use p3, others use 3) if [[ "$DISK" == *nvme* ]] || [[ "$DISK" == *mmcblk* ]]; then WIN_PART="''${DISK}p3" else WIN_PART="''${DISK}3" fi echo "[4/4] Expanding NTFS filesystem on $WIN_PART..." ${pkgs.ntfs3g}/bin/ntfsresize --force --no-action "$WIN_PART" echo "y" | ${pkgs.ntfs3g}/bin/ntfsresize --force "$WIN_PART" echo "" echo "Done. Windows partition expanded to fill $DISK." echo "You can now boot from the disk." ''; }; apps.${system}.toDisk = { type = "app"; program = "${self.packages.${system}.toDisk}/bin/vmix-to-disk"; }; }; }