Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions bin/omarchy-provision-first-run
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ if omarchy-done check "$FIRST_RUN_DONE" && (( force == 0 )); then
exit 0
fi

omarchy-provision-user "${finalize_user_args[@]}" || true

mkdir -p "$state_dir"

FIRST_RUN_LOG="$state_dir/first-run.log"
Expand All @@ -54,6 +52,18 @@ log_first_run() {
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >>"$FIRST_RUN_LOG"
}

# A failed finalization keeps first-run retryable like any other step. Dropping
# the status here used to let the later steps mark first-run complete over a
# user who was never finalized.
log_first_run "Starting: finalize user"
if omarchy-provision-user "${finalize_user_args[@]}"; then
log_first_run "Completed: finalize user"
else
finalize_user_status=$?
first_run_failed=1
log_first_run "Failed: finalize user (exit code: $finalize_user_status)"
fi

run_first_run_step() {
local name="$1"
shift
Expand Down
5 changes: 3 additions & 2 deletions install/hardware/apple/fix-spi-keyboard.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Detect MacBook models that need SPI keyboard modules
product_name="$(cat /sys/class/dmi/id/product_name 2>/dev/null)"
# Detect MacBook models that need SPI keyboard modules.
# Apple Silicon has no DMI; under set -e an unguarded read aborts the hardware pass.
product_name="$(cat /sys/class/dmi/id/product_name 2>/dev/null || true)"
if [[ $product_name =~ MacBook[89],1|MacBook1[02],1|MacBookPro13,[123]|MacBookPro14,[123] ]]; then
echo "Detected MacBook with SPI keyboard"

Expand Down
2 changes: 1 addition & 1 deletion install/hardware/fix-surface-keyboard.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Module list derived from Chris McLeod's manual install instructions
# https://chrismcleod.dev/blog/installing-arch-linux-with-secure-boot-on-a-microsoft-surface-laptop-studio/
if omarchy-hw-surface; then
product_name="$(cat /sys/class/dmi/id/product_name 2>/dev/null)"
product_name="$(cat /sys/class/dmi/id/product_name 2>/dev/null || true)"
echo "Detected Surface Device"

# Modules already exist in the rootfs for the default kernel.
Expand Down
2 changes: 1 addition & 1 deletion install/hardware/intel/lpmd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Meteor Lake (170/172), Lunar Lake (189), Panther Lake (204)

if omarchy-hw-intel && omarchy-battery-present; then
cpu_model=$(grep -m1 "^model\s*:" /proc/cpuinfo 2>/dev/null | cut -d: -f2 | tr -d ' ')
cpu_model=$(grep -m1 "^model\s*:" /proc/cpuinfo 2>/dev/null | cut -d: -f2 | tr -d ' ' || true)
if [[ "$cpu_model" =~ ^(151|154|170|172|183|186|189|191|204)$ ]]; then
omarchy-pkg-add intel-lpmd
sudo systemctl enable intel_lpmd.service
Expand Down
2 changes: 1 addition & 1 deletion install/hardware/intel/thermald.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

if omarchy-hw-intel; then
# Check if Sandy Bridge or newer (model >= 42). Sandy Bridge: model 42 (mobile), 45 (desktop)
cpu_model=$(grep -m1 "^model\s*:" /proc/cpuinfo 2>/dev/null | cut -d: -f2 | tr -d ' ')
cpu_model=$(grep -m1 "^model\s*:" /proc/cpuinfo 2>/dev/null | cut -d: -f2 | tr -d ' ' || true)
cpu_model=${cpu_model:-0}
if ((cpu_model >= 42)) && omarchy-battery-present; then
omarchy-pkg-add thermald
Expand Down
46 changes: 46 additions & 0 deletions test/shell.d/first-run-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,49 @@ if grep -F 'skip-first-run-update-notification' "$ROOT/install/user/first-run/wi
fi

pass "first-run uses one lifecycle completion marker"

# A failed finalization must keep first-run retryable. The old driver discarded
# that status with "|| true" and then marked first-run complete when its later
# steps happened to succeed, so a transient finalization failure permanently
# skipped the user's required setup.
retry_tmp=$(mktemp -d)
trap 'rm -rf "$test_tmp" "$retry_tmp"' EXIT
retry_bin="$retry_tmp/bin"
retry_root="$retry_tmp/omarchy"
mkdir -p "$retry_bin" "$retry_root/install/user/first-run" "$retry_tmp/home"

cat >"$retry_bin/omarchy-done" <<'SH'
#!/bin/bash
case "$1:$2" in
check:first-run-user) exit 1 ;;
mark:first-run-user) touch "$OMARCHY_TEST_FIRST_RUN_MARKER" ;;
esac
SH
cat >"$retry_bin/omarchy-provision-user" <<'SH'
#!/bin/bash
touch "$OMARCHY_TEST_FINALIZE_CALLED"
exit 42
SH
for helper in omarchy-hook-install omarchy-notification-wait; do
printf '#!/bin/bash\nexit 0\n' >"$retry_bin/$helper"
done
chmod +x "$retry_bin"/*

for leaf in welcome.sh timezone.sh wifi.sh enable-user-units.sh gnome-theme.sh \
gtk-primary-paste.sh audio-tuning.sh; do
printf 'exit 0\n' >"$retry_root/install/user/first-run/$leaf"
done

retry_marker="$retry_tmp/first-run-marker"
retry_finalize="$retry_tmp/finalize-called"
HOME="$retry_tmp/home" PATH="$retry_bin:$PATH" OMARCHY_PATH="$retry_root" \
OMARCHY_TEST_FIRST_RUN_MARKER="$retry_marker" \
OMARCHY_TEST_FINALIZE_CALLED="$retry_finalize" \
bash "$ROOT/bin/omarchy-provision-first-run" >"$retry_tmp/output"

[[ -e $retry_finalize ]] || fail "first-run attempts user finalization"
[[ ! -e $retry_marker ]] || fail "failed user finalization keeps first-run retryable"
grep -F 'Failed: finalize user (exit code: 42)' \
"$retry_tmp/home/.local/state/omarchy/first-run.log" >/dev/null ||
fail "first-run records a finalization failure"
pass "failed user finalization keeps first-run retryable"
30 changes: 30 additions & 0 deletions test/shell.d/install-leaf-guards-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/bash

set -euo pipefail

source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"

# run_logged sources every leaf under bash -eE, where an assignment from a
# failing command substitution aborts the leaf, and the abort takes every later
# stage down with it. Hardware probes read sysfs and procfs paths that simply
# do not exist on other machines (Apple Silicon has no DMI), so each probe has
# to tolerate a missing file. Two accepted forms:
# product_name="$(cat /sys/class/dmi/id/product_name 2>/dev/null || true)"
# if product_name=$(cat /sys/class/dmi/id/product_name 2>/dev/null); then
# bash's $(<file) shorthand cannot take || true inside the parens; use the
# if-condition form (or cat) instead.
unguarded=()
while read -r leaf; do
while IFS= read -r line; do
[[ $line == *'|| true'* ]] && continue
[[ $line == *'||'* ]] && continue
[[ $line =~ ^[[:space:]]*(el)?if[[:space:]] ]] && continue
unguarded+=("${leaf#"$ROOT/"}: ${line#"${line%%[![:space:]]*}"}")
done < <(grep -E '\$\([^)]*/(sys|proc)/' "$leaf" || true)
done < <(find "$ROOT/install" -name '*.sh' -type f | sort)

if (( ${#unguarded[@]} )); then
fail "install leaves tolerate a missing sysfs probe" \
"unguarded probes:$(printf '\n %s' "${unguarded[@]}")"
fi
pass "install leaves tolerate a missing sysfs probe"
2 changes: 1 addition & 1 deletion test/shell.d/locate-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ check(not (root / "install/config/locate.sh").exists() and not (root / "migratio
"the retired locate configuration helper and migration are absent")
for directory in ("bin", "install", "migrations"):
for path in (root / directory).rglob("*"):
if path.is_file():
if path.is_file() and path.suffix != ".pyc" and "__pycache__" not in path.parts:
content = path.read_text()
if "OMARCHY_UPDATEDB_CONF_PATH" in content or "config/locate.sh" in content:
raise SystemExit("not ok - retired locate configuration path remains in " + str(path))
Expand Down