Confirm the Start Omarchy Now prompt after provisioning setup (#100)
* Confirm the Start Omarchy Now prompt after provisioning setup First-boot account setup now ends on a celebration screen whose Start Omarchy Now button gates the SDDM handoff, so the provisioning test must press it — same as the installer's Reboot Now prompt — once the pending flag clears. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add a centered greeter before the installer keyboard step Open the ISO configurator with the same greeter the deferred-provisioning first boot uses — vertically centered logo, the Omarchy tagline, and a single button — so install and first boot bookend setup identically. The installer's button reads "Start install"; first boot's reads "Start setup". Co-Authored-By: Claude <noreply@anthropic.com> * Animate the installer greeter logo with a skippable ColorShift Match the first-boot greeter: a looping tte ColorShift over the centered logo with a "Press Return to Start Install" hint instead of a button. Return begins the install at any time. Co-Authored-By: Claude <noreply@anthropic.com> * Theme the installer greeter ColorShift to the Omarchy palette Match the first-boot greeter: sweep the logo ColorShift through the Tokyo Night accent colors instead of tte's default rainbow. Co-Authored-By: Claude <noreply@anthropic.com> * Fix installer greeter ColorShift: green base, no flash, clean handoff Mirror the first-boot greeter fixes: indexed ANSI colors (green base with a cyan accent) because the framebuffer console can't render tte truecolor; one long tte invocation so the loop never flashes; stty sane + clear after Return so the keyboard step starts clean. Co-Authored-By: Claude <noreply@anthropic.com> * Dismiss the greeter in the QEMU test drivers The installer and first-boot flows now open with a greeter (animated logo + tagline). Wait for the tagline and press Return before the keyboard step, in both drive paths, so the harness gets past the greeter. Co-Authored-By: Claude <noreply@anthropic.com> * Kill the installer greeter animation cleanly Run tte directly instead of inside a backgrounded `while` subshell, so killing the tracked PID actually stops the effect. Killing the subshell orphaned tte, which kept painting the logo over the keyboard step. Co-Authored-By: Claude <noreply@anthropic.com> * Guard the greeter wait against set -e in the configurator too Harmless today (no set -e), but keeps the greeter's animation teardown robust if that changes. Co-Authored-By: Claude <noreply@anthropic.com> * Also settle the terminal in emulators, not just real VTs wait_for_stable_terminal skipped terminal emulators on the assumption they're already at final size, but a fresh terminal (or sudo's pty) reports a stale 24x80 for a moment at startup too. Drop the VT-only gate so the greeter centers there as well. Co-Authored-By: Claude <noreply@anthropic.com> * Test harness: drive the first-boot timezone step and direct SDDM handoff Match the deferred-provisioning first-boot flow changes: the owner now picks a timezone after the email step, and setup hands straight off to SDDM instead of pausing on a celebration screen with a Start Omarchy Now button. Drive the new Timezone screen (accept the geo-guessed default) and drop the button confirmation. Co-Authored-By: Claude <noreply@anthropic.com> * Don't bake hostname/timezone into deferred installs; set them at first boot Deferred provisioning defers the user step to first boot, so the machine's owner should name the machine and pick the timezone there — not inherit values chosen at install time. Stop setting hostname/timezone in the configurator's deferred branch: the orchestrator already skips an empty timezone (the system stays UTC until first boot), and it now falls back to a neutral "archlinux" hostname for the install so archinstall still succeeds. The first-boot omarchy-provision-owner form collects and applies both. Harness: drive the new Hostname screen and assert both hostname and timezone actually landed on the running system after first boot. Co-Authored-By: Claude <noreply@anthropic.com> * Match the installer greeter: solid green logo, no color animation Same fix as the first-boot greeter — tte's ColorShift judders on the 16-color framebuffer console (truecolor crush). Show the logo in solid green and drop the animation so both greeters look identical and flash-free. Co-Authored-By: Claude <noreply@anthropic.com> * Harden the provision harness: SSH-blip wait, timezone timeout, hostname assert - The pending-flag wait treated an SSH connection failure (rc 255) the same as "flag absent" (rc 1), so a transient blip during finalization would exit early and snapshot the base mid-finalization. Only break on a clean rc 1; keep waiting on 0 or 255. - Bump the first-boot Timezone screen wait 60s -> 180s (tzupdate geo-guess over first-boot networking can lag; matches the installer's headroom). - Make the applied-hostname check a hard failure (it's deterministic — we typed it), so a first-boot apply regression can't pass green; timezone stays a report since it's geo-guessed. Co-Authored-By: Claude <noreply@anthropic.com> * Seed hostname=omarchy/timezone=UTC in deferred install instead of empties Write neutral valid defaults in the configurator's deferred branch rather than empty strings, and drop the orchestrator's `config.hostname or "archlinux"` fallback (hostname is always non-empty now). The first-boot wizard overwrites both. This keeps the "owner sets them at first boot" behavior without depending on archinstall tolerating empty hostname/timezone at config-load time. Co-Authored-By: Claude <noreply@anthropic.com> * Fix set -e regression in the provision pending-wait loop The previous hardening moved `ssh_guest "test -f pending"` out of the `while` condition into a standalone command, but the harness runs `set -euo pipefail` — so the moment the flag cleared (ssh returns 1, the intended "done" signal) it tripped errexit and aborted the whole run right after provisioning, before the session/acceptance phase. Capture the result with `|| rc=$?` so the non-zero is the signal, not a fatal error. Also guard the follow-on hostname/timezone substitutions with `|| got=""` so a transient SSH failure there can't abort either (an empty value then correctly fails the hostname assertion). Co-Authored-By: Claude <noreply@anthropic.com> * Bring back the installer greeter ColorShift animation Match the first-boot greeter: restore the static green logo + looping tte ColorShift overlay. The framebuffer truecolor crush gives it a quick flash, which is acceptable — both greeters keep the animation. Co-Authored-By: Claude <noreply@anthropic.com> * Skip the install celebration on deferred installs; reboot directly A deferred-provisioning install has nothing to celebrate yet — the owner finishes setup (and gets the send-off) at first boot. So the installer's "Installed Omarchy in ..." screen and the Reboot Now prompt now belong to a direct install only: for a deferred install the dashboard clears and reboots on its own. .automated_script.sh detects deferred mode (the config's defer_provisioning flag, or the cidata defer-provisioning marker) and passes OMARCHY_UI_DEFER_PROVISIONING to the dashboard. Harness: a deferred install no longer shows Reboot Now, so wait_for_install recognizes the auto-reboot by the first-boot greeter tagline appearing. Co-Authored-By: Claude <noreply@anthropic.com> * Detect deferred mode with jq, not a line regex The dashboard's deferred detection grepped user_configuration.json for the defer_provisioning boolean on one line; a reformatted config would read as a direct install and wrongly show the celebration. Parse it with jq using the same path the orchestrator reads (.omarchy_install.defer_provisioning). Co-Authored-By: Claude <noreply@anthropic.com> * Drop Bosnian and Khmer from the installer keyboard picker Match the first-boot picker: neither has a console keymap, so both silently fell back to US. Remove them rather than offer a layout that can't apply. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
81de5087ea
commit
f32247afc3
4 files changed
+172
-15
No files matched your search
+68
-6
@@ -606,6 +606,11 @@ audio-panel|meta_l-ctrl-a|omarchy-keyboard-panel|omarchy.audio'
|
||||
drive_configurator() {
|
||||
log "Driving the installer wizard"
|
||||
|
||||
# A greeter (animated logo + tagline) opens the installer; Return begins.
|
||||
wait_for_screen "Opinionated" 300
|
||||
capture_console "success-installer-00-greeter"
|
||||
press ret
|
||||
|
||||
# Keyboard is the first screen. Ctrl+C there is the hidden entry into deferred provisioning
|
||||
# mode; a normal install just selects the layout.
|
||||
wait_for_screen "keyboard layout" 300
|
||||
@@ -710,7 +715,12 @@ drive_provision_owner() {
|
||||
# verifier can prove the deferred step applied a non-default layout — UK
|
||||
# leaves every letter identical to US, so the typed password (sent as raw
|
||||
# keycodes) still matches the literal one the harness pipes to sudo.
|
||||
wait_for_screen "keyboard layout" 600
|
||||
# A greeter (animated logo + tagline) opens first boot; Return begins.
|
||||
wait_for_screen "Opinionated" 600
|
||||
capture_console "success-provision-00-greeter"
|
||||
press ret
|
||||
|
||||
wait_for_screen "keyboard layout" 120
|
||||
press up
|
||||
capture_console "success-provision-01-keyboard-layout-uk"
|
||||
press ret
|
||||
@@ -743,13 +753,25 @@ drive_provision_owner() {
|
||||
capture_console "success-provision-04-email"
|
||||
press ret
|
||||
|
||||
# Hostname is deferred to first boot too.
|
||||
wait_for_screen "Hostname" 60
|
||||
type_text "$GUEST_HOSTNAME"
|
||||
capture_console "success-provision-05-hostname"
|
||||
press ret
|
||||
|
||||
# Timezone is deferred to first boot too; accept the geo-guessed default.
|
||||
# Generous timeout: the tzupdate geo-guess over first-boot networking can lag.
|
||||
wait_for_screen "Timezone" 180
|
||||
capture_console "success-provision-06-timezone"
|
||||
press ret
|
||||
|
||||
wait_for_screen "look right" 60
|
||||
capture_console "success-provision-05-review"
|
||||
capture_console "success-provision-07-review"
|
||||
press ret
|
||||
|
||||
# Finalization (offline Node unpack, LUKS re-key on encrypted installs)
|
||||
# runs before SDDM appears.
|
||||
capture_console "success-provision-06-finalizing"
|
||||
capture_console "success-provision-08-finalizing"
|
||||
}
|
||||
|
||||
wait_for_install() {
|
||||
@@ -766,6 +788,15 @@ wait_for_install() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Deferred-provisioning installs skip the celebration and reboot on their own
|
||||
# (no Reboot Now prompt); the first-boot greeter tagline appearing means the
|
||||
# install finished and rebooted into setup.
|
||||
if $PROVISION && grep -qi "Opinionated" <<<"$text"; then
|
||||
log "Install finished and auto-rebooted into first-boot setup."
|
||||
capture_console "success-installer-15-autoreboot"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if grep -qi "installation stopped" <<<"$text"; then
|
||||
capture_console "failure-installer-installation-stopped"
|
||||
echo "Install failed — screenshot saved to $RUN_DIR" >&2
|
||||
@@ -965,8 +996,17 @@ install_phase() {
|
||||
# flag to clear before powering off.
|
||||
if $PROVISION; then
|
||||
log "Waiting for provisioning first-boot setup to finish"
|
||||
local waited=0
|
||||
while ssh_guest "test -f /var/lib/omarchy/provisioning/pending" 2>/dev/null; do
|
||||
local waited=0 rc
|
||||
while true; do
|
||||
# Capture rc via `|| rc=$?` so a non-zero result doesn't trip `set -e`
|
||||
# (this command is intentionally allowed to "fail" — that's the signal).
|
||||
rc=0
|
||||
ssh_guest "test -f /var/lib/omarchy/provisioning/pending" 2>/dev/null || rc=$?
|
||||
# rc 0 = flag still present; rc 255 = SSH not up yet (finalization may
|
||||
# still be running) — keep waiting. Only a clean "file absent" (rc 1)
|
||||
# means provisioning finished, so we don't snapshot mid-finalization on a
|
||||
# transient SSH blip.
|
||||
(( rc == 0 || rc == 255 )) || break
|
||||
if ((waited >= 900)); then
|
||||
capture_console "failure-provision-finalization-timeout"
|
||||
echo "Timed out waiting for provisioning first-boot setup to complete" >&2
|
||||
@@ -975,7 +1015,29 @@ install_phase() {
|
||||
sleep 10
|
||||
((waited += 10))
|
||||
done
|
||||
capture_console "success-provision-06-setup-complete"
|
||||
|
||||
# The owner's hostname and timezone are set at first boot now, not baked
|
||||
# into the install — confirm they actually landed on the running system.
|
||||
# Hostname is deterministic (we typed it), so a mismatch is a hard failure;
|
||||
# timezone is geo-guessed, so just report what landed.
|
||||
local got_host="" got_tz=""
|
||||
got_host=$(ssh_guest "cat /etc/hostname" 2>/dev/null | tr -d '\r\n') || got_host=""
|
||||
got_tz=$(ssh_guest "timedatectl show -p Timezone --value" 2>/dev/null | tr -d '\r\n') || got_tz=""
|
||||
if [[ $got_host != "$GUEST_HOSTNAME" ]]; then
|
||||
capture_console "failure-provision-hostname-not-applied"
|
||||
echo "First-boot hostname is '${got_host:-<empty>}', expected '$GUEST_HOSTNAME'" >&2
|
||||
return 1
|
||||
fi
|
||||
log "hostname applied at first boot: $got_host"
|
||||
if [[ -n $got_tz && $got_tz != "UTC" ]]; then
|
||||
log "timezone applied at first boot: $got_tz"
|
||||
else
|
||||
echo "WARN: timezone is '${got_tz:-<empty>}' (expected the owner's choice, not UTC)" >&2
|
||||
fi
|
||||
|
||||
# Deferred first-boot setup hands straight off to SDDM once the oneshot
|
||||
# service exits — no celebration screen, no Start Omarchy button to confirm.
|
||||
capture_console "success-provision-09-handoff"
|
||||
fi
|
||||
|
||||
ssh_guest "echo $GUEST_PASSWORD | sudo -S cat /var/log/omarchy-install-timing.json 2>/dev/null" \
|
||||
|
||||
@@ -101,6 +101,16 @@ else
|
||||
./configurator
|
||||
fi
|
||||
|
||||
# Deferred-provisioning installs skip the celebration/reboot prompt and reboot on
|
||||
# their own — the owner completes setup at first boot. Signalled by the config's
|
||||
# defer_provisioning flag (interactive) or the defer-provisioning marker (cidata).
|
||||
# Parse the flag with jq (the same JSON semantics the orchestrator uses) rather
|
||||
# than a line regex, so a reformatted config can't read as a direct install.
|
||||
if [[ -f /root/defer-provisioning ]] ||
|
||||
[[ "$(jq -r '.omarchy_install.defer_provisioning // false' /root/user_configuration.json 2>/dev/null)" == "true" ]]; then
|
||||
export OMARCHY_UI_DEFER_PROVISIONING=yes
|
||||
fi
|
||||
|
||||
# The foreground dashboard is now the sole visible install UI owner. It starts
|
||||
# the actual installer as a non-interactive child, logs child output, waits for
|
||||
# completion, then renders the final installed-time/reboot prompt itself.
|
||||
|
||||
@@ -42,14 +42,12 @@ measure_terminal
|
||||
# console and only grows once the kernel framebuffer/KMS takes over (noticeably
|
||||
# late in VMs). The logo is wider than 80 columns, so a first draw against that
|
||||
# transient narrow console wraps the logo ("smushed") and can't center it
|
||||
# (padding clamps to 0, so it hugs the left). Every later screen re-measures and
|
||||
# looks right, so this only bites the very first screen. Hold that first draw
|
||||
# until the width settles at (or above) the logo width. Terminal emulators (dry
|
||||
# runs) are already at final size, so skip them; a real VT that never widens
|
||||
# (e.g. nomodeset) still proceeds after the cap rather than hanging.
|
||||
# (padding clamps to 0, so it hugs the left). A terminal emulator (or sudo's
|
||||
# pty) has the same problem the other way: it reports a stale 24x80 for a few
|
||||
# hundred ms after start before its real winsize is set. Either way, hold the
|
||||
# first draw until the width settles at (or above) the logo width. A real VT
|
||||
# that never widens (e.g. nomodeset) still proceeds after the cap.
|
||||
wait_for_stable_terminal() {
|
||||
[[ $(tty 2>/dev/null) == /dev/tty* ]] || return 0
|
||||
|
||||
local width last="" stable=0 waited=0
|
||||
while (( waited < 5000 )); do
|
||||
width=$(stty size 2>/dev/null </dev/tty | awk '{print $2}')
|
||||
@@ -71,6 +69,80 @@ clear_logo() {
|
||||
gum style --foreground 2 --padding "1 0 0 $PADDING_LEFT" "$(<"$LOGO_PATH")"
|
||||
}
|
||||
|
||||
# Vertically-centered welcome shown once before the keyboard step — the same
|
||||
# frame the deferred-provisioning first boot opens on, so install and first boot
|
||||
# bookend the setup identically. Logo, the Omarchy tagline, and a single button,
|
||||
# centered like the boot logo. No animation.
|
||||
greeter() {
|
||||
measure_terminal
|
||||
|
||||
local rows logo_h content_h top cols logo_row tagline_row hint_row
|
||||
local tagline hint tpad hpad anim
|
||||
cols=$TERM_WIDTH
|
||||
rows=$(stty size 2>/dev/null </dev/tty | awk '{print $1}')
|
||||
[[ $rows =~ ^[0-9]+$ ]] || rows=${LINES:-24}
|
||||
logo_h=$(wc -l <"$LOGO_PATH")
|
||||
|
||||
# logo + blank + tagline + blank + hint
|
||||
content_h=$((logo_h + 4))
|
||||
top=$(((rows - content_h) / 2))
|
||||
(( top < 0 )) && top=0
|
||||
logo_row=$((top + 1))
|
||||
tagline_row=$((top + logo_h + 2))
|
||||
hint_row=$((top + logo_h + 4))
|
||||
|
||||
printf '\033[?25l\033[H\033[2J'
|
||||
|
||||
printf '\033[%d;1H' "$logo_row"
|
||||
gum style --foreground 2 --padding "0 0 0 $PADDING_LEFT" "$(<"$LOGO_PATH")"
|
||||
|
||||
tagline="Beautiful, Modern & Opinionated Linux by DHH"
|
||||
tpad=$(((cols - ${#tagline}) / 2)); (( tpad < 0 )) && tpad=0
|
||||
printf '\033[%d;%dH%s' "$tagline_row" "$((tpad + 1))" "$tagline"
|
||||
|
||||
hint="Press Return to Start Install"
|
||||
hpad=$(((cols - ${#hint}) / 2)); (( hpad < 0 )) && hpad=0
|
||||
printf '\033[%d;%dH\033[2m%s\033[0m' "$hint_row" "$((hpad + 1))" "$hint"
|
||||
|
||||
# ColorShift the logo: a green base (indexed color 2) with a cyan accent (6)
|
||||
# drifting through, settling on green. Indexed ANSI colors, not hex — the
|
||||
# framebuffer console can't render tte's truecolor faithfully (it crushes the
|
||||
# palette to a muddy lavender), but the 16 indexed colors map to the Tokyo
|
||||
# Night palette and render true. One long-running invocation (many cycles) so
|
||||
# it never restarts — a restart is what flashed. The effect reads from
|
||||
# /dev/null so it never swallows the Return; --reuse-canvas paints upward from
|
||||
# the saved cursor, anchored one row below the logo.
|
||||
if command -v tte >/dev/null 2>&1; then
|
||||
printf '\033[%d;1H\0337' "$((logo_row + logo_h))"
|
||||
# Run tte directly (not inside a `while` subshell) so $anim is tte's own
|
||||
# PID: killing a wrapping subshell would orphan tte, which then keeps
|
||||
# painting the logo over the keyboard step. --cycles is high enough that it
|
||||
# never ends on its own before Return.
|
||||
tte -i "$LOGO_PATH" \
|
||||
--canvas-width "$cols" \
|
||||
--anchor-text c \
|
||||
--frame-rate 60 \
|
||||
--reuse-canvas \
|
||||
colorshift \
|
||||
--gradient-stops 2 10 6 10 \
|
||||
--gradient-frames 3 \
|
||||
--cycles 1000 \
|
||||
--final-gradient-stops 2 \
|
||||
</dev/null >/dev/tty 2>/dev/null &
|
||||
anim=$!
|
||||
fi
|
||||
|
||||
IFS= read -r _ </dev/tty || true
|
||||
# Tolerate tte's kill signal in `wait` so a future `set -e` here can't abort.
|
||||
[[ -n ${anim:-} ]] && { kill "$anim" 2>/dev/null; wait "$anim" 2>/dev/null || true; }
|
||||
# tte leaves the tty in raw/no-echo mode when killed; restore it or the gum
|
||||
# prompts in the keyboard step that follows silently die.
|
||||
stty sane </dev/tty 2>/dev/null || true
|
||||
# Reset the screen so the leftover animation frame doesn't linger under the
|
||||
# keyboard step that follows.
|
||||
printf '\033[0m\033[H\033[2J\033[?25h'
|
||||
}
|
||||
|
||||
abort() {
|
||||
gum style "${1:-Aborted installation}"
|
||||
echo
|
||||
@@ -116,7 +188,6 @@ keyboard_form() {
|
||||
keyboards=$'Azerbaijani|azerty
|
||||
Belarusian|by
|
||||
Belgian|be-latin1
|
||||
Bosnian|ba
|
||||
Bulgarian|bg-cp1251
|
||||
Croatian|croat
|
||||
Czech|cz
|
||||
@@ -142,7 +213,6 @@ Irish|ie
|
||||
Italian|it
|
||||
Japanese|jp106
|
||||
Kazakh|kazakh
|
||||
Khmer (Cambodia)|khmer
|
||||
Kyrgyz|kyrgyz
|
||||
Lao|la-latin1
|
||||
Latvian|lv
|
||||
@@ -975,6 +1045,8 @@ install_target="full_disk"
|
||||
# isn't measured against the transient 80-column boot console.
|
||||
wait_for_stable_terminal
|
||||
|
||||
greeter
|
||||
|
||||
keyboard_form true
|
||||
|
||||
if $defer_provisioning; then
|
||||
@@ -988,6 +1060,8 @@ if $defer_provisioning; then
|
||||
password_hash=""
|
||||
full_name=""
|
||||
email_address=""
|
||||
# Neutral defaults for the install; the owner overwrites both in the
|
||||
# first-boot OOBE (omarchy-provision-owner).
|
||||
hostname="omarchy"
|
||||
timezone="UTC"
|
||||
|
||||
|
||||
@@ -736,6 +736,17 @@ if (( status != 0 )); then
|
||||
exit "$failure_status"
|
||||
fi
|
||||
|
||||
# Deferred-provisioning installs finish silently and reboot on their own — the
|
||||
# owner completes setup (and sees the send-off) at first boot, so the "Installed
|
||||
# Omarchy in ..." celebration and the Reboot Now prompt belong to a direct
|
||||
# install only.
|
||||
if [[ ${OMARCHY_UI_DEFER_PROVISIONING:-} == "yes" ]]; then
|
||||
printf '%s' "$CLEAR" >"$TTY_PATH" 2>/dev/null || true
|
||||
[[ ${OMARCHY_UI_AUTO_REBOOT:-} == "no" ]] && exit 0
|
||||
reboot 2>/dev/null || systemctl reboot 2>/dev/null || true
|
||||
exit 0
|
||||
fi
|
||||
|
||||
set +e
|
||||
render_finish
|
||||
finish_render_status=$?
|
||||
|
||||
Reference in new issue
Block a user