diff --git a/builder/build-iso.sh b/builder/build-iso.sh index b96045e..e0c322e 100755 --- a/builder/build-iso.sh +++ b/builder/build-iso.sh @@ -2,6 +2,26 @@ set -e +OMARCHY_ISO_REF="${OMARCHY_ISO_REF:-stable}" +OMARCHY_MIRROR="${OMARCHY_MIRROR:-stable}" + +# Stable ISOs install the stable package names. Dev/local-source ISOs install +# the dev packages explicitly rather than relying on pacman's provides=omarchy +# resolution, so the offline mirror and target install show the real package +# names being tested. +case "$OMARCHY_ISO_REF" in + dev|local) + : "${OMARCHY_RUNTIME_PACKAGE:=omarchy-dev}" + : "${OMARCHY_SETTINGS_PACKAGE:=omarchy-settings-dev}" + ;; + *) + : "${OMARCHY_RUNTIME_PACKAGE:=omarchy}" + : "${OMARCHY_SETTINGS_PACKAGE:=omarchy-settings}" + ;; +esac +: "${OMARCHY_NVIM_PACKAGE:=omarchy-nvim}" +export OMARCHY_RUNTIME_PACKAGE OMARCHY_SETTINGS_PACKAGE OMARCHY_NVIM_PACKAGE + # Packages installed into the Arch container used to build the ISO. pacman-key --init pacman --noconfirm -Sy archlinux-keyring @@ -39,15 +59,25 @@ rm -rf "$build_cache_dir/airootfs/etc/xdg/reflector" # Bring in our archiso profile additions. cp -r /configs/* "$build_cache_dir/" +mkdir -p "$build_cache_dir/airootfs/usr/share/omarchy-iso" echo "$OMARCHY_MIRROR" > "$build_cache_dir/airootfs/root/omarchy_mirror" +echo "$OMARCHY_ISO_REF" > "$build_cache_dir/airootfs/root/omarchy_iso_ref" +cat > "$build_cache_dir/airootfs/usr/share/omarchy-iso/package-targets" </dev/null | sed 's/^/omarchy_commit=/' || true @@ -80,9 +110,10 @@ mkdir -p "$build_cache_dir/airootfs/opt/packages/" cp "/tmp/$NODE_FILENAME" "$build_cache_dir/airootfs/opt/packages/" # Packages installed into the live ISO environment itself (NOT the target system). -# omarchy-settings is needed here so its post_install hook drops Omarchy's -# plymouthd.conf into /etc/plymouth before mkarchiso builds the live initramfs. -arch_packages=(linux-t2 git gum jq openssl plymouth python-terminaltexteffects tzupdate omarchy-keyring omarchy-settings lvm2 cryptsetup parted) +# The selected omarchy-settings package is needed here so its post_install hook +# drops Omarchy's plymouthd.conf into /etc/plymouth before mkarchiso builds the +# live initramfs. +arch_packages=(linux-t2 git gum jq openssl plymouth python-terminaltexteffects tzupdate omarchy-keyring "$OMARCHY_SETTINGS_PACKAGE" lvm2 cryptsetup parted) printf '%s\n' "${arch_packages[@]}" >> "$build_cache_dir/packages.x86_64" # Build the offline mirror: everything pacstrap might want during the target @@ -92,10 +123,17 @@ printf '%s\n' "${arch_packages[@]}" >> "$build_cache_dir/packages.x86_64" if [[ -d /omarchy-source ]]; then base_pkg_lists=(/omarchy-source/install/omarchy-base.packages /omarchy-source/install/omarchy-other.packages) else - # Pull the same package lists out of the freshly-downloaded omarchy package - # so we don't need a local checkout in the non-local-source path. - pacman --config /configs/pacman-online-${OMARCHY_MIRROR}.conf --noconfirm -Sw omarchy --cachedir /tmp --dbpath /tmp/offlinedb-bootstrap >/dev/null - omarchy_pkg=$(ls /tmp/omarchy-*.pkg.tar.zst | head -1) + # Pull the same package lists out of the freshly-downloaded Omarchy runtime + # package so we don't need a local checkout in the non-local-source path. + bootstrap_cache_dir=/tmp/omarchy-pkg-bootstrap + rm -rf "$bootstrap_cache_dir" /tmp/offlinedb-bootstrap /tmp/omarchy-pkglists + mkdir -p "$bootstrap_cache_dir" + pacman --config /configs/pacman-online-${OMARCHY_MIRROR}.conf --noconfirm -Sw "$OMARCHY_RUNTIME_PACKAGE" --cachedir "$bootstrap_cache_dir" --dbpath /tmp/offlinedb-bootstrap >/dev/null + omarchy_pkg=$(find "$bootstrap_cache_dir" -maxdepth 1 -type f -name "$OMARCHY_RUNTIME_PACKAGE-*.pkg.tar.zst" | sort | head -1) + if [[ -z $omarchy_pkg ]]; then + echo "ERROR: downloaded package for $OMARCHY_RUNTIME_PACKAGE not found in $bootstrap_cache_dir" >&2 + exit 1 + fi mkdir -p /tmp/omarchy-pkglists bsdtar -xf "$omarchy_pkg" -C /tmp/omarchy-pkglists usr/share/omarchy/install/omarchy-base.packages usr/share/omarchy/install/omarchy-other.packages base_pkg_lists=(/tmp/omarchy-pkglists/usr/share/omarchy/install/omarchy-base.packages /tmp/omarchy-pkglists/usr/share/omarchy/install/omarchy-other.packages) @@ -112,9 +150,9 @@ mapfile -t all_packages < <( cat "$build_cache_dir/packages.x86_64" grep -hv '^#\|^$' "${base_pkg_lists[@]}" grep -hv '^#\|^$' /builder/archinstall.packages - # Always include the Omarchy packages so the target install can find - # the runtime and companion packages in the offline mirror. - printf 'omarchy\nomarchy-settings\nomarchy-nvim\n' + # Always include the selected Omarchy packages so the target install can + # find the runtime and companion packages in the offline mirror. + printf '%s\n' "$OMARCHY_RUNTIME_PACKAGE" "$OMARCHY_SETTINGS_PACKAGE" "$OMARCHY_NVIM_PACKAGE" } | sort -u ) @@ -122,7 +160,13 @@ mapfile -t all_packages < <( # the mirror; strip them from the pacman -Syw list so it doesn't try to fetch # the published versions on top. if [[ -n ${LOCAL_OMARCHY_BUILD:-} ]]; then - all_packages=($(printf '%s\n' "${all_packages[@]}" | grep -vE '^(omarchy|omarchy-settings|omarchy-nvim)$')) + mapfile -t all_packages < <( + printf '%s\n' "${all_packages[@]}" | + grep -Fxv \ + -e "$OMARCHY_RUNTIME_PACKAGE" \ + -e "$OMARCHY_SETTINGS_PACKAGE" \ + -e "$OMARCHY_NVIM_PACKAGE" || true + ) fi mkdir -p /tmp/offlinedb diff --git a/builder/build-omarchy-packages.sh b/builder/build-omarchy-packages.sh index ea4efc0..4c9659c 100755 --- a/builder/build-omarchy-packages.sh +++ b/builder/build-omarchy-packages.sh @@ -32,10 +32,14 @@ chown builder:builder "$work_dir" pacman -Sy --noconfirm +: "${OMARCHY_RUNTIME_PACKAGE:=omarchy-dev}" +: "${OMARCHY_SETTINGS_PACKAGE:=omarchy-settings-dev}" +: "${OMARCHY_NVIM_PACKAGE:=omarchy-nvim}" + packages=( - omarchy-settings - omarchy - omarchy-nvim + "$OMARCHY_SETTINGS_PACKAGE" + "$OMARCHY_RUNTIME_PACKAGE" + "$OMARCHY_NVIM_PACKAGE" ) for pkg in "${packages[@]}"; do @@ -43,6 +47,10 @@ for pkg in "${packages[@]}"; do echo "Building $pkg" echo "----------------------------------------" pkg_work="$work_dir/$pkg" + if [[ ! -d "/omarchy-pkgs/pkgbuilds/$pkg" ]]; then + echo "ERROR: package source not found: /omarchy-pkgs/pkgbuilds/$pkg" >&2 + exit 1 + fi cp -a "/omarchy-pkgs/pkgbuilds/$pkg" "$pkg_work" chown -R builder:builder "$pkg_work" diff --git a/configs/airootfs/root/.automated_script.sh b/configs/airootfs/root/.automated_script.sh index 804c194..a0b2b9d 100644 --- a/configs/airootfs/root/.automated_script.sh +++ b/configs/airootfs/root/.automated_script.sh @@ -13,6 +13,14 @@ set -euo pipefail [[ $(tty) == /dev/tty1 ]] || exit 0 export OMARCHY_MIRROR="$(cat /root/omarchy_mirror)" +if [[ -f /root/omarchy_iso_ref ]]; then + export OMARCHY_ISO_REF="$(cat /root/omarchy_iso_ref)" +fi +if [[ -f /usr/share/omarchy-iso/package-targets ]]; then + # shellcheck disable=SC1091 + source /usr/share/omarchy-iso/package-targets + export OMARCHY_RUNTIME_PACKAGE OMARCHY_SETTINGS_PACKAGE OMARCHY_NVIM_PACKAGE +fi export OMARCHY_PATH=/usr/share/omarchy export OMARCHY_INSTALL=$OMARCHY_PATH/install export OMARCHY_INSTALL_LOG_FILE=/var/log/omarchy-install.log diff --git a/configs/airootfs/root/configurator b/configs/airootfs/root/configurator index a087069..4c27c6e 100644 --- a/configs/airootfs/root/configurator +++ b/configs/airootfs/root/configurator @@ -261,6 +261,13 @@ unset OMARCHY_CONFIGURATOR_PYTHON # installed Omarchy package owns target setup helpers, while the ISO owns the # installer UI that runs before any target packages exist. OMARCHY_PATH="${OMARCHY_PATH:-/usr/share/omarchy}" +if [[ -f /usr/share/omarchy-iso/package-targets ]]; then + # shellcheck disable=SC1091 + source /usr/share/omarchy-iso/package-targets +fi +OMARCHY_RUNTIME_PACKAGE="${OMARCHY_RUNTIME_PACKAGE:-omarchy}" +OMARCHY_SETTINGS_PACKAGE="${OMARCHY_SETTINGS_PACKAGE:-omarchy-settings}" +OMARCHY_NVIM_PACKAGE="${OMARCHY_NVIM_PACKAGE:-omarchy-nvim}" LOGO_PATH="${LOGO_PATH:-$OMARCHY_PATH/logo.txt}" TERM_HEIGHT=${LINES:-24} @@ -1063,7 +1070,8 @@ _EOF_ "base-devel", "git", "omarchy-keyring", - "omarchy" + "$OMARCHY_SETTINGS_PACKAGE", + "$OMARCHY_RUNTIME_PACKAGE" ], "profile_config": { "gfx_driver": null, @@ -1396,7 +1404,8 @@ cat <<-_EOF_ >user_configuration.json "base-devel", "git", "omarchy-keyring", - "omarchy" + "$OMARCHY_SETTINGS_PACKAGE", + "$OMARCHY_RUNTIME_PACKAGE" ], "profile_config": { "gfx_driver": null, diff --git a/configs/airootfs/usr/share/omarchy-iso/orchestrator/phases_impl.py b/configs/airootfs/usr/share/omarchy-iso/orchestrator/phases_impl.py index 9c12538..d8808c0 100644 --- a/configs/airootfs/usr/share/omarchy-iso/orchestrator/phases_impl.py +++ b/configs/airootfs/usr/share/omarchy-iso/orchestrator/phases_impl.py @@ -34,18 +34,95 @@ from .context import InstallContext from .ui import info -# Packages installed BEFORE useradd. omarchy-settings and omarchy-nvim populate -# /etc/skel so the user's home gets seeded correctly, and omarchy-settings now -# also ships the limine/snapper configs (previously omarchy-limine). Target-side -# setup commands are installed later by the omarchy runtime package and executed -# in chroot. -EARLY_BOOTSTRAP_PACKAGES = [ +# Package targets are written by builder/build-iso.sh. Stable ISOs use the +# stable package names, while dev/local-source ISOs install the dev package +# names explicitly instead of relying on provides=omarchy resolution. +def _iso_ref() -> str: + if ref := os.environ.get("OMARCHY_ISO_REF"): + return ref.strip() + + ref_file = Path("/root/omarchy_iso_ref") + if ref_file.exists(): + try: + return ref_file.read_text().strip() + except OSError: + pass + + return "stable" + + +def _default_package_targets() -> dict[str, str]: + if _iso_ref() in {"dev", "local"}: + return { + "runtime": "omarchy-dev", + "settings": "omarchy-settings-dev", + "nvim": "omarchy-nvim", + } + + return { + "runtime": "omarchy", + "settings": "omarchy-settings", + "nvim": "omarchy-nvim", + } + + +def _package_targets() -> dict[str, str]: + targets = _default_package_targets() + + targets_file = Path("/usr/share/omarchy-iso/package-targets") + if targets_file.exists(): + try: + for raw in targets_file.read_text().splitlines(): + line = raw.strip() + if not line or line.startswith("#") or "=" not in line: + continue + key, value = line.split("=", 1) + value = value.strip().strip('"\'') + match key.strip(): + case "OMARCHY_RUNTIME_PACKAGE": + targets["runtime"] = value + case "OMARCHY_SETTINGS_PACKAGE": + targets["settings"] = value + case "OMARCHY_NVIM_PACKAGE": + targets["nvim"] = value + except OSError: + pass + + env_to_key = { + "OMARCHY_RUNTIME_PACKAGE": "runtime", + "OMARCHY_SETTINGS_PACKAGE": "settings", + "OMARCHY_NVIM_PACKAGE": "nvim", + } + for env_name, key in env_to_key.items(): + if value := os.environ.get(env_name): + targets[key] = value + + return targets + + +def _omarchy_runtime_package() -> str: + return _package_targets()["runtime"] + + +def _omarchy_settings_package() -> str: + return _package_targets()["settings"] + + +def _omarchy_nvim_package() -> str: + return _package_targets()["nvim"] + + +# Packages installed BEFORE useradd. The selected omarchy-settings package and +# omarchy-nvim populate /etc/skel so the user's home gets seeded correctly, and +# omarchy-settings also ships the limine/snapper configs. Target-side setup +# commands are installed later by the selected Omarchy runtime package and +# executed in chroot. +EARLY_BOOTSTRAP_BASE_PACKAGES = [ "base-devel", "git", "limine", "efibootmgr", "omarchy-keyring", - "omarchy-settings", ] # Install LuaRocks before omarchy-nvim pulls in lua51-lpeg. Arch's lua-luarocks @@ -58,15 +135,21 @@ EARLY_LUAROCKS_PACKAGES = [ "luarocks", ] -EARLY_USER_SEED_PACKAGES = [ - "omarchy-nvim", -] -EARLY_PACKAGES = [ - *EARLY_BOOTSTRAP_PACKAGES, - *EARLY_LUAROCKS_PACKAGES, - *EARLY_USER_SEED_PACKAGES, -] +def _early_bootstrap_packages() -> list[str]: + return [*EARLY_BOOTSTRAP_BASE_PACKAGES, _omarchy_settings_package()] + + +def _early_user_seed_packages() -> list[str]: + return [_omarchy_nvim_package()] + + +def _early_packages() -> list[str]: + return [ + *_early_bootstrap_packages(), + *EARLY_LUAROCKS_PACKAGES, + *_early_user_seed_packages(), + ] # ───────────────────────────────────────────────────────────────────────────── @@ -533,14 +616,17 @@ DEFERRED_BOOT_HOOKS = ( def _install_early_packages(installer) -> None: - info(f"› installing early Omarchy packages: {', '.join(EARLY_BOOTSTRAP_PACKAGES)}") - installer.add_additional_packages(EARLY_BOOTSTRAP_PACKAGES) + bootstrap_packages = _early_bootstrap_packages() + user_seed_packages = _early_user_seed_packages() + + info(f"› installing early Omarchy packages: {', '.join(bootstrap_packages)}") + installer.add_additional_packages(bootstrap_packages) info(f"› installing LuaRocks prerequisites: {', '.join(EARLY_LUAROCKS_PACKAGES)}") installer.add_additional_packages(EARLY_LUAROCKS_PACKAGES) - info(f"› installing user seed packages: {', '.join(EARLY_USER_SEED_PACKAGES)}") - installer.add_additional_packages(EARLY_USER_SEED_PACKAGES) + info(f"› installing user seed packages: {', '.join(user_seed_packages)}") + installer.add_additional_packages(user_seed_packages) def _is_devnull_symlink(path: Path) -> bool: @@ -587,16 +673,23 @@ def _unmask_mkinitcpio_pacman_hooks(ctx: InstallContext) -> None: def _runtime_package_list(ctx: InstallContext) -> list[str]: - """omarchy + every package in the ISO-bundled base package list that - isn't already in EARLY_PACKAGES.""" + """Selected Omarchy runtime package + every package in the ISO-bundled + base package list that isn't already installed early.""" base_pkgs_file = Path("/usr/share/omarchy-iso/omarchy-base.packages") - pkgs = ["omarchy"] - early = set(EARLY_PACKAGES) + pkgs = [_omarchy_runtime_package()] + already_installed = set(_early_packages()) | { + _omarchy_runtime_package(), + _omarchy_settings_package(), + _omarchy_nvim_package(), + "omarchy", + "omarchy-settings", + "omarchy-nvim", + } for raw in base_pkgs_file.read_text().splitlines(): s = raw.strip() if not s or s.startswith("#"): continue - if s not in early and s not in pkgs: + if s not in already_installed and s not in pkgs: pkgs.append(s) return pkgs @@ -956,6 +1049,10 @@ def _run_target_setup_command(ctx: InstallContext, cmd: list[str], *, user: str f"OMARCHY_USER_NAME={ctx.full_name}", f"OMARCHY_USER_EMAIL={ctx.email}", f"OMARCHY_MIRROR={mirror_channel}", + f"OMARCHY_ISO_REF={_iso_ref()}", + f"OMARCHY_RUNTIME_PACKAGE={_omarchy_runtime_package()}", + f"OMARCHY_SETTINGS_PACKAGE={_omarchy_settings_package()}", + f"OMARCHY_NVIM_PACKAGE={_omarchy_nvim_package()}", "OMARCHY_INSTALL_LOG_FILE=/var/log/omarchy-install.log", "OMARCHY_LOG_TO_STDOUT=1", ]