From f6775344f63ce612f10b1684acde0d0e71eb1d69 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 16 Jul 2026 09:48:21 -0700 Subject: [PATCH] Offer easy way to test partitioned install --- README.md | 6 + bin/omarchy-iso-boot | 1 - bin/omarchy-iso-test-windows-disk | 295 ++++++++++++++++++++++++++++++ 3 files changed, 301 insertions(+), 1 deletion(-) create mode 100755 bin/omarchy-iso-test-windows-disk diff --git a/README.md b/README.md index de4fd91..5b41e57 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,12 @@ Use `--dev` or `--rc` to build against those package channels. Both `--dev` and Run `./bin/omarchy-iso-boot [release/omarchy.iso]`. +To exercise installation alongside existing Windows-style partitions, run +`./bin/omarchy-iso-test-windows-disk [release/omarchy.iso]`. It creates a +synthetic disk in `/tmp` with an existing ESP and data partition plus ample +unallocated space, then offers to start an interactive installation on it. The +fixture exercises Windows partition preservation but does not contain Windows. + ## Signing the ISO Run `./bin/omarchy-iso-sign [release/omarchy.iso]`. The signing key is retrieved from the shared Omarchy vault with the 1Password CLI. diff --git a/bin/omarchy-iso-boot b/bin/omarchy-iso-boot index 78a90d8..f1dba98 100755 --- a/bin/omarchy-iso-boot +++ b/bin/omarchy-iso-boot @@ -130,7 +130,6 @@ if [[ -z ${WAYLAND_DISPLAY:-} && -z ${DISPLAY:-} ]]; then exit 1 fi -DISK="/tmp/omarchy-iso-boot.qcow2" if [[ ! -f $DISK || $REUSE != "reuse" ]]; then qemu-img create -f qcow2 "$DISK" 40G cp /usr/share/edk2/x64/OVMF_VARS.4m.fd "$OVMF_VARS" diff --git a/bin/omarchy-iso-test-windows-disk b/bin/omarchy-iso-test-windows-disk new file mode 100755 index 0000000..d245f33 --- /dev/null +++ b/bin/omarchy-iso-test-windows-disk @@ -0,0 +1,295 @@ +#!/bin/bash + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(dirname "$SCRIPT_DIR")" + +TEST_DISK="${OMARCHY_ISO_TEST_WINDOWS_DISK:-/tmp/omarchy-iso-test-windows.qcow2}" +TEST_OVMF_VARS="${OMARCHY_ISO_TEST_WINDOWS_OVMF_VARS:-/tmp/OVMF_VARS.omarchy-iso-test-windows.fd}" +DISK_SIZE_GIB=96 +MIN_FREE_GIB=64 +RECREATE=0 +ISO="" + +ACTIVE_NBD="" +MOUNT_DIR="" +MOUNTED=0 +TEMPORARY_DISK="" + +usage() { + cat < 0 )); do + case "$1" in + --recreate) + RECREATE=1 + shift + ;; + -h|--help) + usage + exit 0 + ;; + -*) + echo "Unknown option: $1" >&2 + usage >&2 + exit 2 + ;; + *) + if [[ -n $ISO ]]; then + echo "Only one ISO may be specified." >&2 + usage >&2 + exit 2 + fi + ISO="$1" + shift + ;; + esac +done + +cleanup_mount() { + if (( MOUNTED )); then + sudo umount "$MOUNT_DIR" >/dev/null 2>&1 || true + MOUNTED=0 + fi + if [[ -n $MOUNT_DIR ]]; then + rmdir "$MOUNT_DIR" >/dev/null 2>&1 || true + MOUNT_DIR="" + fi +} + +disconnect_disk() { + cleanup_mount + if [[ -n $ACTIVE_NBD ]]; then + sudo qemu-nbd --disconnect "$ACTIVE_NBD" >/dev/null 2>&1 || true + ACTIVE_NBD="" + fi +} + +cleanup() { + disconnect_disk + [[ -z $TEMPORARY_DISK ]] || rm -f "$TEMPORARY_DISK" +} + +trap cleanup EXIT +trap 'exit 130' INT +trap 'exit 143' TERM + +find_free_nbd() { + local device + for device in /sys/class/block/nbd*; do + [[ -e $device ]] || continue + [[ ! -e $device/pid ]] || continue + printf '/dev/%s\n' "${device##*/}" + return 0 + done + return 1 +} + +connect_disk() { + local disk="$1" mode="${2:-read-write}" + local -a options=(--format=qcow2) + + ACTIVE_NBD="$(find_free_nbd)" || { + echo "No unused NBD device is available." >&2 + return 1 + } + [[ $mode == read-only ]] && options+=(--read-only) + + if ! sudo qemu-nbd "${options[@]}" --connect="$ACTIVE_NBD" "$disk"; then + ACTIVE_NBD="" + return 1 + fi + if ! sudo udevadm settle; then + disconnect_disk + return 1 + fi +} + +mount_partition() { + local partition="$1" + MOUNT_DIR="$(mktemp -d)" || return 1 + if ! sudo mount -o "${2:-defaults}" "$partition" "$MOUNT_DIR"; then + rmdir "$MOUNT_DIR" >/dev/null 2>&1 || true + MOUNT_DIR="" + return 1 + fi + MOUNTED=1 +} + +largest_free_region() { + sudo parted -ms "$1" unit B print free /dev/null | + awk -F: ' + $NF ~ /free/ { + size=$4 + gsub(/B/, "", size) + if (size+0 > max+0) max=size + } + END { print max+0 } + ' +} + +validate_test_disk() { + local part_count pttype free_space_b min_free_b + local esp data valid=1 + + [[ -f $TEST_DISK ]] || return 1 + qemu-img check -q "$TEST_DISK" >/dev/null 2>&1 || return 1 + connect_disk "$TEST_DISK" read-only || return 1 + + esp="${ACTIVE_NBD}p1" + data="${ACTIVE_NBD}p2" + part_count=$(lsblk -nro TYPE "$ACTIVE_NBD" | awk '$1 == "part" { count++ } END { print count+0 }') + pttype=$(lsblk -dnro PTTYPE "$ACTIVE_NBD" 2>/dev/null || true) + free_space_b=$(largest_free_region "$ACTIVE_NBD") + min_free_b=$((MIN_FREE_GIB * 1024 * 1024 * 1024)) + + [[ $pttype == gpt ]] || valid=0 + (( part_count == 2 )) || valid=0 + (( free_space_b >= min_free_b )) || valid=0 + [[ $(sudo blkid -s TYPE -o value "$esp" 2>/dev/null || true) == vfat ]] || valid=0 + [[ $(sudo blkid -s LABEL -o value "$esp" 2>/dev/null || true) == WINDOWS_ESP ]] || valid=0 + [[ $(sudo blkid -s TYPE -o value "$data" 2>/dev/null || true) == ext4 ]] || valid=0 + [[ $(sudo blkid -s LABEL -o value "$data" 2>/dev/null || true) == WINDOWS_DATA ]] || valid=0 + + if (( valid )); then + mount_partition "$esp" ro || valid=0 + if (( valid )); then + sudo test -d "$MOUNT_DIR/EFI/Microsoft" || valid=0 + fi + cleanup_mount + fi + + if (( valid )); then + mount_partition "$data" ro || valid=0 + if (( valid )); then + sudo test -f "$MOUNT_DIR/OMARCHY-MUST-NOT-TOUCH.txt" || valid=0 + fi + cleanup_mount + fi + + disconnect_disk + (( valid )) +} + +create_test_disk() { + local esp data + + mkdir -p "$(dirname "$TEST_DISK")" + TEMPORARY_DISK="${TEST_DISK}.creating.$$" + rm -f "$TEMPORARY_DISK" + + gum style --foreground 6 "Creating synthetic Windows test disk at $TEST_DISK" + qemu-img create -f qcow2 "$TEMPORARY_DISK" "${DISK_SIZE_GIB}G" + connect_disk "$TEMPORARY_DISK" + + sudo parted --script "$ACTIVE_NBD" mklabel gpt + sudo parted --script "$ACTIVE_NBD" mkpart WINDOWS_ESP fat32 1MiB 513MiB + sudo parted --script "$ACTIVE_NBD" set 1 esp on + sudo parted --script "$ACTIVE_NBD" mkpart WINDOWS_DATA ext4 513MiB 20GiB + sudo partprobe "$ACTIVE_NBD" + sudo udevadm settle + + esp="${ACTIVE_NBD}p1" + data="${ACTIVE_NBD}p2" + sudo mkfs.fat -F32 -n WINDOWS_ESP "$esp" >/dev/null + sudo mkfs.ext4 -F -L WINDOWS_DATA "$data" >/dev/null 2>&1 + + mount_partition "$esp" + sudo mkdir -p "$MOUNT_DIR/EFI/Microsoft/Boot" + printf '%s\n' 'Synthetic Windows ESP for Omarchy ISO testing.' | + sudo tee "$MOUNT_DIR/EFI/Microsoft/README.txt" >/dev/null + cleanup_mount + + mount_partition "$data" + printf '%s\n' 'This existing partition must survive the Omarchy installation.' | + sudo tee "$MOUNT_DIR/OMARCHY-MUST-NOT-TOUCH.txt" >/dev/null + cleanup_mount + + sync + disconnect_disk + mv -f "$TEMPORARY_DISK" "$TEST_DISK" + TEMPORARY_DISK="" +} + +select_iso() { + local -a isos=() + + if [[ -n $ISO ]]; then + [[ -f $ISO ]] || { + echo "ISO not found: $ISO" >&2 + return 1 + } + realpath "$ISO" + return 0 + fi + + mapfile -t isos < <( + find "$REPO_ROOT/release" -maxdepth 1 -type f -name '*.iso' -printf '%T@ %p\n' 2>/dev/null | + sort -nr | + cut -d' ' -f2- + ) + (( ${#isos[@]} > 0 )) || { + echo "No ISO found under $REPO_ROOT/release." >&2 + return 1 + } + + printf '%s\n' "${isos[@]}" | gum choose --header "Select ISO to install" +} + +omarchy-pkg-add qemu-full edk2-ovmf parted dosfstools e2fsprogs +sudo modprobe nbd max_part=16 + +if [[ -f $TEST_DISK ]] && (( ! RECREATE )); then + gum style --foreground 6 "Verifying existing test disk at $TEST_DISK" + if validate_test_disk; then + gum style --foreground 2 "✓ Synthetic Windows test disk is ready" + elif gum confirm --default=false "The existing test disk is not a pristine fixture. Recreate it?"; then + create_test_disk + else + gum style "Left the existing disk untouched." + exit 0 + fi +else + create_test_disk +fi + +# The synthetic fixture has no real Windows bootloader, so reset OVMF state for +# every run. The ISO still sees EFI/Microsoft and must leave that ESP untouched. +mkdir -p "$(dirname "$TEST_OVMF_VARS")" +cp /usr/share/edk2/x64/OVMF_VARS.4m.fd "$TEST_OVMF_VARS" + +gum style --border rounded --padding "0 1" --border-foreground 6 \ + "Synthetic Windows disk ready" \ + "Disk: $TEST_DISK" \ + "Layout: 512MiB Windows ESP + existing data + 64GiB+ free" + +if gum confirm "Start installation on this disk?"; then + ISO="$(select_iso)" + trap - EXIT INT TERM + exec "$SCRIPT_DIR/omarchy-iso-boot" \ + --reuse \ + --disk "$TEST_DISK" \ + --ovmf-vars "$TEST_OVMF_VARS" \ + "$ISO" \ + -- -boot once=d,menu=on +fi