feat: Avoid ISO rebuilding for dramatically faster preparation (#2032)

This commit is contained in:
Kroese
2026-07-31 22:05:55 +02:00
committed by GitHub
parent 2f7e3d1903
commit aa9584df90
8 changed files with 1614 additions and 972 deletions
+192 -25
View File
@@ -11,6 +11,7 @@ SHUTDOWN_SIGNAL=0
QEMU_PTY="$QEMU_DIR/qemu.pty"
QEMU_END="$QEMU_DIR/qemu.end"
ACPI_SOCKET="$QEMU_DIR/acpi.sock"
CONSOLE_PID="$QEMU_DIR/console.pid"
CONSOLE_SOCKET="$QEMU_DIR/console.sock"
QEMU_START_PID="$QEMU_DIR/qemu.start.pid"
@@ -28,56 +29,96 @@ bootStatus() {
last="${line#*:}"
recent=$(tail -n +"${line%%:*}" "$QEMU_PTY")
if [[ "$last" == "Booting from DVD/CD"* ]]; then
return 0
fi
grep -Fq "Loading FreeLoader..." <<< "$recent" && return 0
grep -Fq \
if grep -Fq \
-e "No bootable device." \
-e "BOOTMGR is missing" \
-e "Boot failed: not a bootable disk" \
-e "Boot failed: could not read the boot disk" \
<<< "$recent" && return 1
<<< "$recent"; then
return 2
fi
return 0
if grep -Fq \
-e "Boot failed: not a bootable disk" \
-e "Boot failed: Could not read from CDROM" \
-e "Boot failed: could not read the boot disk" \
<<< "$recent"; then
return 5
fi
if [[ "$last" == "Booting from Hard Disk"* ]]; then
return 3
fi
if [[ "$last" == "Booting from DVD/CD"* ]]; then
return 4
fi
return 1
fi
grep -Fq "UEFI Interactive Shell" "$QEMU_PTY" && return 2
local line last recent
local last
last=$(grep -E \
line=$(grep -nE \
'BdsDxe: starting Boot[[:xdigit:]]{4} ' \
"$QEMU_PTY" | tail -1)
[ -z "$last" ] && return 1
[ -z "$line" ] && return 1
last="${line#*:}"
recent=$(tail -n +"${line%%:*}" "$QEMU_PTY")
if [[ "$last" == *'"Windows Boot Manager"'* ]]; then
return 0
fi
grep -Eq \
'BdsDxe: failed to start Boot[[:xdigit:]]{4} "UEFI QEMU .*DVD-ROM.*: Time out' \
<<< "$recent" && return 2
grep -Fq "UEFI Interactive Shell" <<< "$recent" && return 2
grep -Eq \
-e '"Windows Boot Manager"' \
-e '"UEFI QEMU .*DVD-ROM' \
-e 'CDROM\(' \
-e 'USB\(' \
<<< "$last"
<<< "$last" && return 4
return 1
}
waitForBoot() {
local pid="$1"
local timeout="${2:-30}"
local keySent=0
local pendingType=0
local pendingLine=""
local pendingDeadline=0
local keyDelay status marker
local deadline=$((SECONDS + timeout))
local screen="visit http://127.0.0.1:$WEB_PORT/ to view the screen..."
while isAlive "$pid"; do
if (( ! keySent )) && needsBootKey; then
if keyDelay=$(bootKeyDelay); then
if sendKey spc "$keyDelay" 500; then
keySent=1
fi
fi
fi
if bootStatus; then
local status=0
status=0
else
local status=$?
status=$?
fi
case "$status" in
0) echo
if [[ "${DISPLAY,,}" == "web" ]] && ! disabled "${WEB:-Y}"; then
@@ -90,9 +131,47 @@ waitForBoot() {
2) echo
error "$(app) could not boot, aborting..."
terminateQemu
return 0 ;;
error "$(app) could not boot, aborting..."
terminateQemu
return 0 ;;
3 | 4)
marker=$(getBootMarker)
if [[ "$marker" != "$pendingLine" ]] || (( status != pendingType )); then
pendingLine="$marker"
pendingType=$status
pendingDeadline=$((SECONDS + 6))
fi
if (( pendingDeadline > 0 && SECONDS >= pendingDeadline )); then
echo
if [[ "${DISPLAY,,}" == "web" ]] && ! disabled "${WEB:-Y}"; then
info "$(app) started successfully, $screen"
else
info "$(app) started successfully."
fi
echo && return 0
fi
;;
5)
pendingType=0
pendingLine=""
pendingDeadline=0
;;
*)
pendingType=0
pendingLine=""
pendingDeadline=0
;;
esac
@@ -101,7 +180,7 @@ waitForBoot() {
sleep 0.25
done
! isAlive "$pid" && return 0
isAlive "$pid" || return 0
[ -f "$QEMU_END" ] && return 0
error "Timeout while waiting for QEMU to boot the machine, aborting..."
@@ -149,12 +228,100 @@ ready() {
"$QEMU_PTY" | tail -1)
grep -Eq \
'BdsDxe: starting Boot[[:xdigit:]]{4} "Windows Boot Manager" from HD\(' \
'BdsDxe: starting Boot[[:xdigit:]]{4} "Windows Boot Manager" from .*HD\(' \
<<< "$last" && return 0
return 1
}
sendKey() {
local key="$1"
local delay="${2:-0}"
local hold="${3:-100}"
local output
[ ! -S "$ACPI_SOCKET" ] && return 1
[[ "$delay" != "0" ]] && sleep "$delay"
if ! output=$(
printf 'sendkey %s %s\n' "$key" "$hold" |
nc -q 1 -w 1 -U "$ACPI_SOCKET" 2>&1
); then
return 1
fi
if grep -Eqi \
-e 'unknown command' \
-e 'unknown key' \
-e 'invalid parameter' \
-e 'invalid key' \
-e '^error:' \
<<< "$output"; then
warn "failed to send boot key through QEMU monitor!"
if enabled "${DEBUG:-}"; then
echo "$output"
fi
return 1
fi
return 0
}
supportsBootKey() {
local id="$1"
[[ "${id,,}" == "win"* ]]
}
needsBootKey() {
[ ! -s "$BOOT" ] && return 1
[[ "${BOOT,,}" != *".iso" ]] && return 1
[ -f "$STORAGE/windows.boot" ] && return 1
supportsBootKey "$DETECTED"
}
bootKeyDelay() {
[ ! -s "$QEMU_PTY" ] && return 1
if grep -Fq "Press any key to" "$QEMU_PTY"; then
echo 0
return 0
fi
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
grep -Fq "Booting from DVD/CD" "$QEMU_PTY" || return 1
else
grep -Eq \
'BdsDxe: starting Boot[[:xdigit:]]{4} "UEFI QEMU .*DVD-ROM' \
"$QEMU_PTY" || return 1
fi
echo 0.5
return 0
}
getBootMarker() {
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
grep -nE '^Booting from (Hard Disk|DVD/CD)' "$QEMU_PTY" | tail -1
return 0
fi
grep -nE \
'BdsDxe: starting Boot[[:xdigit:]]{4} ' \
"$QEMU_PTY" | tail -1
return 0
}
markWindowsBooted() {
local file="$STORAGE/windows.boot"
@@ -164,7 +331,7 @@ markWindowsBooted() {
fi
# Remove CD-ROM ISO after install
! ready && return 0
ready || return 0
if ! touch "$file"; then
warn "failed to create Windows installation marker!"
@@ -288,7 +455,7 @@ gracefulShutdown() {
finish "$code"
}
! enabled "$SHUTDOWN" && return 0
enabled "$SHUTDOWN" || return 0
[ -n "${QEMU_TIMEOUT:-}" ] && TIMEOUT="$QEMU_TIMEOUT"
if interactive; then