From 8153da36b84823f5ef4a4a504eb61ee6714b71d2 Mon Sep 17 00:00:00 2001 From: Softer Date: Fri, 24 Apr 2026 12:40:52 +0300 Subject: [PATCH 1/5] Add developer VM script for faster testing iteration Introduces dev_vm.sh, a QEMU launcher paired with a minimal archiso-built dev ISO. The project source is shared read-only into the guest over 9p, so host edits appear live inside the VM without rebuilding the ISO on every change. The guest auto-mounts the share at /root/archinstall-dev and aliases `archinstall` to `python -m archinstall` from that path. The runtime package list is derived at build time from pyproject.toml so the script stays in sync with upstream dependencies automatically. OVMF paths are probed across Arch, Debian/Ubuntu, and Fedora layouts, and an Arch-based host is verified via /etc/os-release before pacman. .gitignore: whitelist dev_vm.sh under the existing **/**.sh blanket and ignore the .dev-iso/ and .dev-configs/ artifact folders. --- .gitignore | 3 + dev_vm.sh | 272 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100755 dev_vm.sh diff --git a/.gitignore b/.gitignore index 376bdbd535..45ddacb771 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ SAFETY_LOCK **/**.egg* **/**.sh !archinstall/locales/locales_generator.sh +!dev_vm.sh **/**.egg-info/ **/**build/ **/**src/ @@ -39,5 +40,7 @@ requirements.txt /.gitconfig /actions-runner /cmd_output.txt +/.dev-iso/ +/.dev-configs/ node_modules/ uv.lock diff --git a/dev_vm.sh b/dev_vm.sh new file mode 100755 index 0000000000..9ce5bdc494 --- /dev/null +++ b/dev_vm.sh @@ -0,0 +1,272 @@ +#!/bin/bash +# Dev test VM for archinstall. +# Builds a minimal dev ISO on first run (runtime deps pre-installed, 9p shares +# auto-mounted, `archinstall` aliased to `python -m archinstall`), then launches +# QEMU. Source lives on the host, guest mounts it read-only - no rebuild loop. +# +# Host artifacts (created in repo root, all git-ignored): +# .dev-iso/ generated dev ISO (mkarchiso output) +# .dev-disk.qcow2 VM disk image (qemu-img) +# .dev-ovmf-vars.fd persistent UEFI NVRAM (copied from OVMF_VARS) +# .dev-configs/ optional, user-created - shared rw to guest as /root/cfg +# +# Inside the guest after boot: +# /root/archinstall-dev project source (9p ro, host edits appear live) +# /root/cfg .dev-configs share (9p rw, mounted only if folder exists) +# archinstall alias for `python -m archinstall` +# +# Usage: +# ./dev_vm.sh - build ISO if missing, fresh disk, boot +# ./dev_vm.sh rebuild | r - force rebuild ISO, fresh disk, boot +# ./dev_vm.sh keep | k - reuse disk, boot ISO +# ./dev_vm.sh boot | b - boot from installed disk (no ISO) +# ./dev_vm.sh clean | c - remove disk, NVRAM, ISO +# ./dev_vm.sh -h - show this help +# +# Env overrides: +# SCREEN_W, SCREEN_H - virtio-vga resolution (default 1280x720) +# +# Host FS note: 9p mapped-xattr mode needs xattr support on the filesystem +# holding the repo (ext4/btrfs work out of the box; ZFS requires xattr=sa). + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_DIR="$SCRIPT_DIR" +CONFIGS_DIR="$SCRIPT_DIR/.dev-configs" +ISO_DIR="$SCRIPT_DIR/.dev-iso" +DISK="$SCRIPT_DIR/.dev-disk.qcow2" +OVMF_VARS="$SCRIPT_DIR/.dev-ovmf-vars.fd" +DISK_SIZE="30G" +RAM="4G" +CPUS="4" +SCREEN_W="${SCREEN_W:-1280}" +SCREEN_H="${SCREEN_H:-720}" +ARG="${1:-default}" + +# OVMF firmware - probed at runtime across common distro paths +OVMF_CODE="" +OVMF_VARS_ORIG="" + +err() { echo "ERROR: $*" >&2; exit 1; } + +probe_ovmf() { + local pairs=( + "/usr/share/edk2/x64/OVMF_CODE.4m.fd:/usr/share/edk2/x64/OVMF_VARS.4m.fd" + "/usr/share/edk2-ovmf/x64/OVMF_CODE.fd:/usr/share/edk2-ovmf/x64/OVMF_VARS.fd" + "/usr/share/edk2/ovmf/OVMF_CODE.fd:/usr/share/edk2/ovmf/OVMF_VARS.fd" + "/usr/share/OVMF/OVMF_CODE_4M.fd:/usr/share/OVMF/OVMF_VARS_4M.fd" + "/usr/share/OVMF/OVMF_CODE.fd:/usr/share/OVMF/OVMF_VARS.fd" + ) + local pair code vars + for pair in "${pairs[@]}"; do + code="${pair%%:*}" + vars="${pair##*:}" + if [ -f "$code" ] && [ -f "$vars" ]; then + OVMF_CODE="$code" + OVMF_VARS_ORIG="$vars" + return 0 + fi + done + err "OVMF firmware not found. Install 'edk2-ovmf' (Arch), 'ovmf' (Debian/Ubuntu), or 'edk2-ovmf' (Fedora)." +} + +check_host_deps() { + local missing=() cmd + for cmd in qemu-system-x86_64 qemu-img sudo; do + command -v "$cmd" >/dev/null 2>&1 || missing+=("$cmd") + done + if [ ${#missing[@]} -gt 0 ]; then + err "missing host commands: ${missing[*]} (install qemu-base and sudo)" + fi +} + +# ISO build needs pacman + mkarchiso, which are Arch-only. Accept Arch and +# Arch-based derivatives (Manjaro, EndeavourOS, ...) via ID / ID_LIKE. +check_arch_host() { + local id="" id_like="" + if [ -r /etc/os-release ]; then + # shellcheck disable=SC1091 + . /etc/os-release + id="${ID:-}" + id_like="${ID_LIKE:-}" + fi + if [ "$id" != "arch" ] && [[ "$id_like" != *arch* ]]; then + err "ISO build requires an Arch-based host (pacman + mkarchiso). Detected ID='${id:-unknown}', ID_LIKE='${id_like:-unknown}'." + fi +} + +# Parse runtime deps from pyproject.toml and map to Arch package names. +# Assumes the `python-` convention, which holds for every archinstall +# dependency today. If a future dep breaks the convention, fix here. +derive_packages() { + command -v python3 >/dev/null 2>&1 || err "python3 not found on host (needed to parse pyproject.toml)" + local result + result=$(python3 - "$PROJECT_DIR/pyproject.toml" <<'PY' +import re +import sys +import tomllib + +with open(sys.argv[1], 'rb') as f: + data = tomllib.load(f) +for dep in data['project']['dependencies']: + name = re.split(r'[<>=!~;\[\s]', dep, maxsplit=1)[0].strip() + if name: + # PEP 503: lowercase, any run of [-_.] becomes '-'. Arch mirrors this + # naming, so normalize before prepending the python- prefix. + name = re.sub(r'[-_.]+', '-', name).lower() + print(f'python-{name}') +PY +) || err "failed to parse $PROJECT_DIR/pyproject.toml" + [ -n "$result" ] || err "pyproject.toml has no [project.dependencies]" + printf '%s\n' "$result" +} + +find_iso() { + ls -t "$ISO_DIR"/archlinux-*-x86_64.iso 2>/dev/null | head -n1 +} + +build_iso() { + check_arch_host + if ! command -v mkarchiso >/dev/null 2>&1; then + echo ">>> mkarchiso not found on host; archiso will be installed via sudo pacman." + fi + local runtime_deps + runtime_deps=$(derive_packages) + echo ">>> Runtime deps derived from pyproject.toml:" + echo "$runtime_deps" | sed 's/^/ /' + echo ">>> Building dev ISO (sudo needed for pacman/mkarchiso)..." + sudo env OUT_DIR="$ISO_DIR" HOST_USER="$(id -un)" RUNTIME_DEPS="$runtime_deps" bash <<'SUDO_SCRIPT' +set -e +BUILD_DIR=/tmp/archlive-dev + +# Runtime deps - python plus the list derived from pyproject.toml on the host. +# Source comes via 9p, no wheel build needed. +packages=(python) +while IFS= read -r p; do + [ -n "$p" ] && packages+=("$p") +done <<< "$RUNTIME_DEPS" + +rm -rf "$BUILD_DIR" +pacman --noconfirm --needed -S archiso +cp -r /usr/share/archiso/configs/releng "$BUILD_DIR" + +# Drop preinstalled archinstall - we run from 9p-mounted source. +# Anchored pattern so related packages (archinstall-*, python-archinstall-*) +# would not be accidentally removed if releng ever grows them. +sed -i '/^archinstall$/d' "$BUILD_DIR/packages.x86_64" +for p in "${packages[@]}"; do + echo "$p" >> "$BUILD_DIR/packages.x86_64" +done + +# Auto-mount project, alias archinstall, print info on login +mkdir -p "$BUILD_DIR/airootfs/root" +cat > "$BUILD_DIR/airootfs/root/.zprofile" <<'ZP' +mkdir -p /root/archinstall-dev /root/cfg +if ! mount -t 9p -o trans=virtio,ro dev /root/archinstall-dev 2>/dev/null; then + echo "ERROR: failed to mount 9p 'dev' share. The archinstall alias will not work." + echo "Check host qemu virtfs support and that the guest kernel has the 9p module." +fi +mount -t 9p -o trans=virtio cfg /root/cfg 2>/dev/null || true +cd /root/archinstall-dev +export PYTHONDONTWRITEBYTECODE=1 +alias archinstall='python -m archinstall' +cat <>> ISO built." +} + +case "$ARG" in + -h|--help|help) + sed -n '2,/^$/p' "$0" | sed 's/^# \{0,1\}//' + exit 0 + ;; + clean|c) + rm -fv "$DISK" "$OVMF_VARS" + rm -rf "$ISO_DIR" + exit 0 + ;; + boot|b) + check_host_deps + probe_ovmf + [ -f "$DISK" ] || err "Disk missing, run without args first" + BOOT_ORDER="c" + ATTACH_ISO=false + ;; + rebuild|r) + check_host_deps + probe_ovmf + rm -rf "$ISO_DIR" + build_iso + rm -f "$DISK" + qemu-img create -f qcow2 "$DISK" "$DISK_SIZE" + BOOT_ORDER="d" + ATTACH_ISO=true + ;; + keep|k) + check_host_deps + probe_ovmf + [ -f "$DISK" ] || err "Disk missing, run without args first" + [ -n "$(find_iso)" ] || build_iso + BOOT_ORDER="d" + ATTACH_ISO=true + ;; + default) + check_host_deps + probe_ovmf + [ -n "$(find_iso)" ] || build_iso + rm -f "$DISK" + qemu-img create -f qcow2 "$DISK" "$DISK_SIZE" + BOOT_ORDER="d" + ATTACH_ISO=true + ;; + *) + err "Unknown argument: $ARG (try -h)" + ;; +esac + +[ -f "$OVMF_VARS" ] || cp "$OVMF_VARS_ORIG" "$OVMF_VARS" + +QEMU_ARGS=( + -machine q35 + -cpu host + -enable-kvm + -m "$RAM" + -smp "$CPUS" + -drive "file=$DISK,format=qcow2,if=virtio" + -device virtio-net-pci,netdev=net0 + -netdev user,id=net0 + -device "virtio-vga,xres=$SCREEN_W,yres=$SCREEN_H" + -display gtk,zoom-to-fit=off + -monitor stdio + -drive "if=pflash,format=raw,readonly=on,file=$OVMF_CODE" + -drive "if=pflash,format=raw,file=$OVMF_VARS" + -virtfs "local,path=$PROJECT_DIR,mount_tag=dev,security_model=mapped-xattr,readonly=on" + -boot "order=$BOOT_ORDER" +) + +# Optional second 9p share for test configs, only if host folder exists +if [ -d "$CONFIGS_DIR" ]; then + QEMU_ARGS+=(-virtfs "local,path=$CONFIGS_DIR,mount_tag=cfg,security_model=mapped-xattr") +fi + +if [ "$ATTACH_ISO" = "true" ]; then + ISO="$(find_iso)" + [ -n "$ISO" ] && [ -f "$ISO" ] || err "No dev ISO after build step" + QEMU_ARGS+=(-cdrom "$ISO") +fi + +exec qemu-system-x86_64 "${QEMU_ARGS[@]}" From 3829bbe80b40ee188a78cd5e7f3c2b880d218a3d Mon Sep 17 00:00:00 2001 From: Softer Date: Sun, 26 Apr 2026 14:20:15 +0300 Subject: [PATCH 2/5] Move dev_vm.sh under scripts/ and split out Python helper Address svartkanin's review on #4470. Two related changes: - Move dev_vm.sh to scripts/dev_vm.sh and split SCRIPT_DIR (where the script lives) from PROJECT_DIR (project root, parent of scripts/). All .dev-* artifact paths now anchor on PROJECT_DIR so they still land in the repo root where .gitignore matches them. Both invocations work: ./scripts/dev_vm.sh from project root and ./dev_vm.sh from inside scripts/. - Extract the inline pyproject.toml parser from a bash heredoc into scripts/derive_packages.py. Same logic, less mixed-language noise. The whole-script bash -> Python question is left open until @Torxed weighs in on principled inclusion of dev tooling in archinstall. --- scripts/derive_packages.py | 33 +++++++++++++++++++++++ dev_vm.sh => scripts/dev_vm.sh | 48 +++++++++++++--------------------- 2 files changed, 51 insertions(+), 30 deletions(-) create mode 100755 scripts/derive_packages.py rename dev_vm.sh => scripts/dev_vm.sh (86%) diff --git a/scripts/derive_packages.py b/scripts/derive_packages.py new file mode 100755 index 0000000000..1f84774d2e --- /dev/null +++ b/scripts/derive_packages.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +"""Parse pyproject.toml runtime dependencies and emit Arch package names. + +Assumes the python- convention, which holds for every archinstall +dependency today. If a future dep breaks the convention, fix here. +""" + +import re +import sys +import tomllib + + +def main() -> int: + if len(sys.argv) != 2: + print(f'usage: {sys.argv[0]} ', file=sys.stderr) + return 1 + + with open(sys.argv[1], 'rb') as f: + data = tomllib.load(f) + + for dep in data['project']['dependencies']: + name = re.split(r'[<>=!~;\[\s]', dep, maxsplit=1)[0].strip() + if name: + # PEP 503: lowercase, any run of [-_.] becomes '-'. Arch mirrors this + # naming, so normalize before prepending the python- prefix. + name = re.sub(r'[-_.]+', '-', name).lower() + print(f'python-{name}') + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/dev_vm.sh b/scripts/dev_vm.sh similarity index 86% rename from dev_vm.sh rename to scripts/dev_vm.sh index 9ce5bdc494..5a5dc7df5d 100755 --- a/dev_vm.sh +++ b/scripts/dev_vm.sh @@ -15,13 +15,16 @@ # /root/cfg .dev-configs share (9p rw, mounted only if folder exists) # archinstall alias for `python -m archinstall` # -# Usage: -# ./dev_vm.sh - build ISO if missing, fresh disk, boot -# ./dev_vm.sh rebuild | r - force rebuild ISO, fresh disk, boot -# ./dev_vm.sh keep | k - reuse disk, boot ISO -# ./dev_vm.sh boot | b - boot from installed disk (no ISO) -# ./dev_vm.sh clean | c - remove disk, NVRAM, ISO -# ./dev_vm.sh -h - show this help +# Run from the project root or from inside scripts/ - both work, the script +# resolves the project root from its own location. +# +# Usage (from project root): +# ./scripts/dev_vm.sh - build ISO if missing, fresh disk, boot +# ./scripts/dev_vm.sh rebuild | r - force rebuild ISO, fresh disk, boot +# ./scripts/dev_vm.sh keep | k - reuse disk, boot ISO +# ./scripts/dev_vm.sh boot | b - boot from installed disk (no ISO) +# ./scripts/dev_vm.sh clean | c - remove disk, NVRAM, ISO +# ./scripts/dev_vm.sh -h - show this help # # Env overrides: # SCREEN_W, SCREEN_H - virtio-vga resolution (default 1280x720) @@ -32,11 +35,11 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -PROJECT_DIR="$SCRIPT_DIR" -CONFIGS_DIR="$SCRIPT_DIR/.dev-configs" -ISO_DIR="$SCRIPT_DIR/.dev-iso" -DISK="$SCRIPT_DIR/.dev-disk.qcow2" -OVMF_VARS="$SCRIPT_DIR/.dev-ovmf-vars.fd" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +CONFIGS_DIR="$PROJECT_DIR/.dev-configs" +ISO_DIR="$PROJECT_DIR/.dev-iso" +DISK="$PROJECT_DIR/.dev-disk.qcow2" +OVMF_VARS="$PROJECT_DIR/.dev-ovmf-vars.fd" DISK_SIZE="30G" RAM="4G" CPUS="4" @@ -97,27 +100,12 @@ check_arch_host() { } # Parse runtime deps from pyproject.toml and map to Arch package names. -# Assumes the `python-` convention, which holds for every archinstall -# dependency today. If a future dep breaks the convention, fix here. +# Delegates to derive_packages.py so the Python logic lives in a real .py file. derive_packages() { command -v python3 >/dev/null 2>&1 || err "python3 not found on host (needed to parse pyproject.toml)" local result - result=$(python3 - "$PROJECT_DIR/pyproject.toml" <<'PY' -import re -import sys -import tomllib - -with open(sys.argv[1], 'rb') as f: - data = tomllib.load(f) -for dep in data['project']['dependencies']: - name = re.split(r'[<>=!~;\[\s]', dep, maxsplit=1)[0].strip() - if name: - # PEP 503: lowercase, any run of [-_.] becomes '-'. Arch mirrors this - # naming, so normalize before prepending the python- prefix. - name = re.sub(r'[-_.]+', '-', name).lower() - print(f'python-{name}') -PY -) || err "failed to parse $PROJECT_DIR/pyproject.toml" + result=$(python3 "$SCRIPT_DIR/derive_packages.py" "$PROJECT_DIR/pyproject.toml") \ + || err "failed to parse $PROJECT_DIR/pyproject.toml" [ -n "$result" ] || err "pyproject.toml has no [project.dependencies]" printf '%s\n' "$result" } From 328b7f8adb76ff3f38d82f603015bcf827616c63 Mon Sep 17 00:00:00 2001 From: Softer Date: Sun, 26 Apr 2026 14:40:21 +0300 Subject: [PATCH 3/5] Include git in dev ISO Add git to the package list and pre-trust the 9p-mounted source in /etc/gitconfig so `git status` / `log` / `diff` work on it out of the box. The 9p share comes in with host UIDs that do not match the guest, which would otherwise trip git's safe.directory dubious-ownership check. --- scripts/dev_vm.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/dev_vm.sh b/scripts/dev_vm.sh index 5a5dc7df5d..70ad5b2627 100755 --- a/scripts/dev_vm.sh +++ b/scripts/dev_vm.sh @@ -130,7 +130,7 @@ BUILD_DIR=/tmp/archlive-dev # Runtime deps - python plus the list derived from pyproject.toml on the host. # Source comes via 9p, no wheel build needed. -packages=(python) +packages=(python git) while IFS= read -r p; do [ -n "$p" ] && packages+=("$p") done <<< "$RUNTIME_DEPS" @@ -147,6 +147,14 @@ for p in "${packages[@]}"; do echo "$p" >> "$BUILD_DIR/packages.x86_64" done +# Trust the 9p-mounted source for git: host UIDs differ from the guest's, +# which would otherwise trip git's safe.directory dubious-ownership check. +mkdir -p "$BUILD_DIR/airootfs/etc" +cat > "$BUILD_DIR/airootfs/etc/gitconfig" <<'GIT' +[safe] + directory = /root/archinstall-dev +GIT + # Auto-mount project, alias archinstall, print info on login mkdir -p "$BUILD_DIR/airootfs/root" cat > "$BUILD_DIR/airootfs/root/.zprofile" <<'ZP' From 79f5db554480afb2ee61123724a6d8ab0989c6bc Mon Sep 17 00:00:00 2001 From: Softer Date: Sun, 26 Apr 2026 18:33:13 +0300 Subject: [PATCH 4/5] Update dev_vm.sh whitelist path after move under scripts/ --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 45ddacb771..940f41eb30 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ SAFETY_LOCK **/**.egg* **/**.sh !archinstall/locales/locales_generator.sh -!dev_vm.sh +!scripts/dev_vm.sh **/**.egg-info/ **/**build/ **/**src/ From 868d6d1c1389bc4212fd707413eb2fb15fe4c186 Mon Sep 17 00:00:00 2001 From: Softer Date: Tue, 28 Apr 2026 13:33:50 +0300 Subject: [PATCH 5/5] Share /var/log/archinstall via 9p in dev VM and clear it per run Replace the plain `archinstall` alias with a function that wipes the log directory contents before each run, and add a third 9p share so the guest log directory is backed by .dev-logs/ on the host. The host can now tail install.log live without re-entering the VM, and successive iterations start with an empty log without rebooting. The wipe uses find -mindepth 1 -delete because /var/log/archinstall is a 9p mountpoint - removing the directory itself would unmount the share. Cleanup: dev_vm.sh clean now also removes .dev-logs/. --- .gitignore | 1 + scripts/dev_vm.sh | 37 +++++++++++++++++++++++++++---------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 940f41eb30..38ad5e2946 100644 --- a/.gitignore +++ b/.gitignore @@ -42,5 +42,6 @@ requirements.txt /cmd_output.txt /.dev-iso/ /.dev-configs/ +/.dev-logs/ node_modules/ uv.lock diff --git a/scripts/dev_vm.sh b/scripts/dev_vm.sh index 70ad5b2627..6347e1109e 100755 --- a/scripts/dev_vm.sh +++ b/scripts/dev_vm.sh @@ -1,19 +1,22 @@ #!/bin/bash # Dev test VM for archinstall. # Builds a minimal dev ISO on first run (runtime deps pre-installed, 9p shares -# auto-mounted, `archinstall` aliased to `python -m archinstall`), then launches -# QEMU. Source lives on the host, guest mounts it read-only - no rebuild loop. +# auto-mounted, `archinstall` wrapped to clear logs and run `python -m archinstall`), +# then launches QEMU. Source lives on the host, guest mounts it read-only - no rebuild loop. # # Host artifacts (created in repo root, all git-ignored): # .dev-iso/ generated dev ISO (mkarchiso output) # .dev-disk.qcow2 VM disk image (qemu-img) # .dev-ovmf-vars.fd persistent UEFI NVRAM (copied from OVMF_VARS) # .dev-configs/ optional, user-created - shared rw to guest as /root/cfg +# .dev-logs/ auto-created - shared rw to guest as /var/log/archinstall # # Inside the guest after boot: # /root/archinstall-dev project source (9p ro, host edits appear live) # /root/cfg .dev-configs share (9p rw, mounted only if folder exists) -# archinstall alias for `python -m archinstall` +# /var/log/archinstall .dev-logs share (9p rw, host can tail install.log live) +# archinstall wrapper around `python -m archinstall`; clears the +# log directory on every invocation # # Run from the project root or from inside scripts/ - both work, the script # resolves the project root from its own location. @@ -23,7 +26,7 @@ # ./scripts/dev_vm.sh rebuild | r - force rebuild ISO, fresh disk, boot # ./scripts/dev_vm.sh keep | k - reuse disk, boot ISO # ./scripts/dev_vm.sh boot | b - boot from installed disk (no ISO) -# ./scripts/dev_vm.sh clean | c - remove disk, NVRAM, ISO +# ./scripts/dev_vm.sh clean | c - remove disk, NVRAM, ISO, logs # ./scripts/dev_vm.sh -h - show this help # # Env overrides: @@ -37,6 +40,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" CONFIGS_DIR="$PROJECT_DIR/.dev-configs" +LOGS_DIR="$PROJECT_DIR/.dev-logs" ISO_DIR="$PROJECT_DIR/.dev-iso" DISK="$PROJECT_DIR/.dev-disk.qcow2" OVMF_VARS="$PROJECT_DIR/.dev-ovmf-vars.fd" @@ -155,24 +159,32 @@ cat > "$BUILD_DIR/airootfs/etc/gitconfig" <<'GIT' directory = /root/archinstall-dev GIT -# Auto-mount project, alias archinstall, print info on login +# Auto-mount project, define archinstall wrapper, print info on login mkdir -p "$BUILD_DIR/airootfs/root" cat > "$BUILD_DIR/airootfs/root/.zprofile" <<'ZP' -mkdir -p /root/archinstall-dev /root/cfg +mkdir -p /root/archinstall-dev /root/cfg /var/log/archinstall if ! mount -t 9p -o trans=virtio,ro dev /root/archinstall-dev 2>/dev/null; then - echo "ERROR: failed to mount 9p 'dev' share. The archinstall alias will not work." + echo "ERROR: failed to mount 9p 'dev' share. The archinstall wrapper will not work." echo "Check host qemu virtfs support and that the guest kernel has the 9p module." fi mount -t 9p -o trans=virtio cfg /root/cfg 2>/dev/null || true +mount -t 9p -o trans=virtio logs /var/log/archinstall 2>/dev/null || true cd /root/archinstall-dev export PYTHONDONTWRITEBYTECODE=1 -alias archinstall='python -m archinstall' +# Wrapper instead of a plain alias so each invocation starts with a clean log +# directory. The directory is a 9p mount from the host, so the contents are +# wiped (find -delete) instead of removing the mountpoint itself. +archinstall() { + find /var/log/archinstall -mindepth 1 -delete 2>/dev/null + python -m archinstall "$@" +} cat <