Make setup ISO-only
Remove legacy online installer entrypoints, collapse migrations for 4.0, and move setup responsibilities into target-side system, hardware, and user commands.
This commit is contained in:
@@ -135,9 +135,6 @@ assert_output_contains "bare share help uses canonical route" "$output" "omarchy
|
||||
output=$("$CLI" menu share)
|
||||
assert_output_contains "bare required-arg filename route renders CLI help" "$output" "omarchy share <clipboard|file|folder> [path...]"
|
||||
|
||||
output=$("$CLI" branch set)
|
||||
assert_output_contains "bare required-choice route renders CLI help" "$output" "omarchy branch set <master|rc|dev>"
|
||||
|
||||
CLI="$CLI" python3 <<'PY'
|
||||
import json
|
||||
import os
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Ensure the offline/chroot finalizer reaches target-side scripts with no
|
||||
# controlling tty. This specifically protects against finalize.sh sourcing the
|
||||
# interactive helper bundle (presentation/errors) before the parent can capture
|
||||
# a useful failure.
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
TMP="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
|
||||
mkdir -p \
|
||||
"$TMP/install/helpers" \
|
||||
"$TMP/install/packaging" \
|
||||
"$TMP/install/user" \
|
||||
"$TMP/install/config" \
|
||||
"$TMP/install/login" \
|
||||
"$TMP/install/post-install" \
|
||||
"$TMP/omarchy/applications/icons" \
|
||||
"$TMP/omarchy/bin" \
|
||||
"$TMP/omarchy/config" \
|
||||
"$TMP/omarchy/default/alacritty" \
|
||||
"$TMP/omarchy/default/hypr/toggles" \
|
||||
"$TMP/omarchy/default/nautilus-python/extensions" \
|
||||
"$TMP/omarchy/default/omarchy-skill" \
|
||||
"$TMP/omarchy/migrations" \
|
||||
"$TMP/home"
|
||||
|
||||
cp "$ROOT/install/helpers/mode.sh" "$TMP/install/helpers/"
|
||||
cp "$ROOT/install/helpers/chroot.sh" "$TMP/install/helpers/"
|
||||
cp "$ROOT/install/helpers/logging.sh" "$TMP/install/helpers/"
|
||||
ln -s "$TMP/install" "$TMP/omarchy/install"
|
||||
|
||||
cat >"$TMP/install/user/all.sh" <<'SCRIPT'
|
||||
run_logged "$OMARCHY_INSTALL/packaging/marker.sh"
|
||||
install_mode_is offline
|
||||
echo user-marker >>"$OMARCHY_INSTALL_LOG_FILE"
|
||||
stop_install_log
|
||||
touch "$HOME/finalizer-completed"
|
||||
SCRIPT
|
||||
|
||||
cat >"$TMP/install/packaging/marker.sh" <<'SCRIPT'
|
||||
echo packaging-marker
|
||||
SCRIPT
|
||||
|
||||
for script in icons webapps tuis npm; do
|
||||
cat >"$TMP/install/packaging/$script.sh" <<'SCRIPT'
|
||||
:
|
||||
SCRIPT
|
||||
done
|
||||
|
||||
cat >"$TMP/install/post-install/finished.sh" <<'SCRIPT'
|
||||
stop_install_log
|
||||
touch "$HOME/finalizer-completed"
|
||||
return 0 2>/dev/null || exit 0
|
||||
SCRIPT
|
||||
|
||||
cat >"$TMP/omarchy/default/bashrc" <<'EOF'
|
||||
# test bashrc
|
||||
EOF
|
||||
cat >"$TMP/omarchy/default/alacritty/Alacritty.desktop" <<'EOF'
|
||||
[Desktop Entry]
|
||||
Name=Alacritty
|
||||
Type=Application
|
||||
Exec=true
|
||||
EOF
|
||||
cat >"$TMP/omarchy/default/hypr/toggles/flags.lua" <<'EOF'
|
||||
return {}
|
||||
EOF
|
||||
: >"$TMP/omarchy/default/nautilus-python/extensions/localsend.py"
|
||||
: >"$TMP/omarchy/default/nautilus-python/extensions/transcode.py"
|
||||
cat >"$TMP/omarchy/icon.txt" <<'EOF'
|
||||
icon
|
||||
EOF
|
||||
cat >"$TMP/omarchy/logo.txt" <<'EOF'
|
||||
logo
|
||||
EOF
|
||||
cat >"$TMP/omarchy/applications/test.desktop" <<'EOF'
|
||||
[Desktop Entry]
|
||||
Name=Test
|
||||
Type=Application
|
||||
Exec=true
|
||||
EOF
|
||||
: >"$TMP/omarchy/applications/icons/Test.png"
|
||||
|
||||
for cmd in gtk-update-icon-cache update-desktop-database xdg-mime xdg-settings xdg-user-dirs-update; do
|
||||
cat >"$TMP/omarchy/bin/$cmd" <<'SCRIPT'
|
||||
#!/bin/bash
|
||||
:
|
||||
SCRIPT
|
||||
chmod +x "$TMP/omarchy/bin/$cmd"
|
||||
done
|
||||
|
||||
if grep -Eq '^[[:space:]]*(source|\.)[[:space:]].*helpers/all\.sh' "$ROOT/finalize.sh"; then
|
||||
echo "finalize.sh must not source helpers/all.sh" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
output="$({
|
||||
setsid -w env \
|
||||
OMARCHY_INSTALL="$TMP/install" \
|
||||
OMARCHY_PATH="$TMP/omarchy" \
|
||||
OMARCHY_INSTALL_MODE=offline \
|
||||
OMARCHY_CHROOT_FINALIZER=1 \
|
||||
OMARCHY_INSTALL_LOG_FILE="$TMP/omarchy-install.log" \
|
||||
HOME="$TMP/home" \
|
||||
USER=ryan \
|
||||
bash "$ROOT/finalize.sh" </dev/null
|
||||
} 2>&1)"
|
||||
|
||||
printf '%s\n' "$output"
|
||||
|
||||
if [[ ! -f "$TMP/home/finalizer-completed" ]]; then
|
||||
echo "expected finalizer completion marker" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q 'packaging-marker' "$TMP/omarchy-install.log"; then
|
||||
echo "expected run_logged script output in install log" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q 'user-marker' "$TMP/omarchy-install.log"; then
|
||||
echo "expected sourced user scripts to run" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $output == *$'\033[?25h'* ]]; then
|
||||
echo "offline finalizer leaked cursor escape" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $output == *'Inappropriate ioctl'* || $output == *'/dev/tty'* ]]; then
|
||||
echo "offline finalizer attempted tty access" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f "$TMP/home/finalizer-completed" "$TMP/omarchy-install.log"
|
||||
debug_output="$({
|
||||
setsid -w env \
|
||||
OMARCHY_INSTALL_DEBUG=1 \
|
||||
OMARCHY_INSTALL="$TMP/install" \
|
||||
OMARCHY_PATH="$TMP/omarchy" \
|
||||
OMARCHY_INSTALL_MODE=offline \
|
||||
OMARCHY_CHROOT_FINALIZER=1 \
|
||||
OMARCHY_INSTALL_LOG_FILE="$TMP/omarchy-install.log" \
|
||||
HOME="$TMP/home" \
|
||||
USER=ryan \
|
||||
bash "$ROOT/finalize.sh" </dev/null
|
||||
} 2>&1)"
|
||||
|
||||
printf '%s\n' "$debug_output"
|
||||
|
||||
if [[ ! -f "$TMP/home/finalizer-completed" ]]; then
|
||||
echo "expected debug finalizer completion marker" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q '\[finalize-debug\] tracing enabled' "$TMP/omarchy-install.log"; then
|
||||
echo "expected finalize debug trace marker in install log" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q 'source .*/helpers/mode.sh' "$TMP/omarchy-install.log"; then
|
||||
echo "expected helper source trace in debug install log" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q 'packaging-marker' "$TMP/omarchy-install.log"; then
|
||||
echo "expected debug run_logged script output in install log" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $debug_output == *'Inappropriate ioctl'* || $debug_output == *'/dev/tty'* ]]; then
|
||||
echo "debug offline finalizer attempted tty access" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "offline finalizer bootstrap test passed"
|
||||
+3
-189
@@ -4,15 +4,8 @@ set -euo pipefail
|
||||
|
||||
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||
|
||||
TMPDIR=""
|
||||
|
||||
export PATH="$ROOT/bin:$PATH"
|
||||
|
||||
cleanup() {
|
||||
[[ -n $TMPDIR && -d $TMPDIR ]] && rm -rf "$TMPDIR"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
require_command jq
|
||||
require_command python3
|
||||
|
||||
@@ -94,185 +87,6 @@ if missing or bad:
|
||||
PY
|
||||
pass "default bar widget ids resolve to manifests and entry points"
|
||||
|
||||
migration=$(grep -rl 'Place the system update indicator next to weather in the bar' "$ROOT/migrations" | head -n 1 || true)
|
||||
[[ -n $migration ]] || fail "update placement migration exists"
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
mkdir -p "$TMPDIR/home/.config/omarchy"
|
||||
|
||||
cat >"$TMPDIR/home/.config/omarchy/shell.json" <<'JSON'
|
||||
{
|
||||
"version": 1,
|
||||
"bar": {
|
||||
"layout": {
|
||||
"left": [{ "id": "omarchy.menu" }, { "id": "omarchy.workspaces" }],
|
||||
"center": [{ "id": "omarchy.clock" }, { "id": "omarchy.weather" }],
|
||||
"right": [{ "id": "omarchy.tray" }, { "id": "omarchy.bluetooth" }]
|
||||
}
|
||||
},
|
||||
"plugins": []
|
||||
}
|
||||
JSON
|
||||
|
||||
HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-config-shell-bar add omarchy.tailscale
|
||||
jq -e '
|
||||
def ids: map(.id // .);
|
||||
.bar.layout.right | ids == ["omarchy.tray", "omarchy.tailscale", "omarchy.bluetooth"]
|
||||
' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null
|
||||
pass "shell config appends widgets to right by default"
|
||||
|
||||
HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-config-shell-bar add local.left left
|
||||
jq -e '
|
||||
def ids: map(.id // .);
|
||||
.bar.layout.left | ids == ["omarchy.menu", "omarchy.workspaces", "local.left"]
|
||||
' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null
|
||||
pass "shell config appends left widgets after workspaces"
|
||||
|
||||
HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-config-shell-bar add local.center center
|
||||
jq -e '
|
||||
def ids: map(.id // .);
|
||||
.bar.layout.center | ids == ["omarchy.clock", "omarchy.weather", "local.center"]
|
||||
' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null
|
||||
pass "shell config appends center widgets after weather"
|
||||
|
||||
HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-config-shell-bar add local.first right
|
||||
jq -e '
|
||||
def ids: map(.id // .);
|
||||
.bar.layout.right | ids == ["omarchy.tray", "local.first", "omarchy.tailscale", "omarchy.bluetooth"]
|
||||
' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null
|
||||
pass "shell config moves existing widgets without duplicates"
|
||||
|
||||
HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-config-shell-bar show | jq -e '
|
||||
def ids: map(.id // .);
|
||||
(.layout.right | ids == ["omarchy.tray", "local.first", "omarchy.tailscale", "omarchy.bluetooth"]) and
|
||||
has("version") | not
|
||||
' >/dev/null
|
||||
pass "shell config shows only bar json"
|
||||
|
||||
HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-config-shell-bar list --json | jq -e '
|
||||
any(.[]; .id == "omarchy.system-stats" and .addable == true and .inBar == false) and
|
||||
all(.[]; .id != "omarchy.tailscale")
|
||||
' >/dev/null
|
||||
pass "shell config lists addable bar widgets"
|
||||
|
||||
HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-config-shell-bar list --json --all | jq -e '
|
||||
any(.[]; .id == "omarchy.tailscale" and .inBar == true and .addable == false) and
|
||||
any(.[]; .id == "omarchy.indicators" and .addable == true)
|
||||
' >/dev/null
|
||||
pass "shell config list --all includes current widget status"
|
||||
|
||||
HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-config-shell-bar position bottom
|
||||
jq -e '
|
||||
.bar.position == "bottom" and
|
||||
.plugins == []
|
||||
' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null
|
||||
pass "shell config sets bar position"
|
||||
|
||||
HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-config-shell-bar transparent true
|
||||
jq -e '
|
||||
.bar.transparent == true and
|
||||
.bar.position == "bottom" and
|
||||
.plugins == []
|
||||
' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null
|
||||
pass "shell config sets bar transparency"
|
||||
|
||||
HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-config-shell-bar drop local.left
|
||||
jq -e '
|
||||
def ids: map(.id // .);
|
||||
(.bar.layout.left | ids == ["omarchy.menu", "omarchy.workspaces"]) and
|
||||
(.bar.layout.center | ids == ["omarchy.clock", "omarchy.weather", "local.center"]) and
|
||||
(.bar.layout.right | ids == ["omarchy.tray", "local.first", "omarchy.tailscale", "omarchy.bluetooth"])
|
||||
' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null
|
||||
pass "shell config drops widgets from any section"
|
||||
|
||||
HOME="$TMPDIR/home" OMARCHY_PATH="$ROOT" omarchy-config-shell-bar remove local.center
|
||||
jq -e '
|
||||
def ids: map(.id // .);
|
||||
.bar.layout.center | ids == ["omarchy.clock", "omarchy.weather"]
|
||||
' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null
|
||||
pass "shell config removes widgets with remove alias"
|
||||
|
||||
cat >"$TMPDIR/home/.config/omarchy/shell.json" <<'JSON'
|
||||
{
|
||||
"version": 1,
|
||||
"bar": {
|
||||
"position": "top",
|
||||
"transparent": false,
|
||||
"centerAnchor": "omarchy.clock",
|
||||
"layout": {
|
||||
"left": [{ "id": "omarchy.menu" }],
|
||||
"center": [
|
||||
{ "id": "omarchy.clock", "format": "HH:mm" },
|
||||
{ "id": "omarchy.weather", "refreshMinutes": 30 },
|
||||
{ "id": "omarchy.indicators", "items": ["Dnd", "NightLight"] },
|
||||
{ "id": "omarchy.system-update", "custom": true }
|
||||
],
|
||||
"right": [{ "id": "omarchy.audio" }]
|
||||
}
|
||||
},
|
||||
"plugins": [{ "id": "custom.plugin", "enabled": true }]
|
||||
}
|
||||
JSON
|
||||
|
||||
HOME="$TMPDIR/home" bash "$migration"
|
||||
|
||||
jq -e '
|
||||
def ids: map(.id // .);
|
||||
.bar.layout.center | ids == [
|
||||
"omarchy.clock",
|
||||
"omarchy.weather",
|
||||
"omarchy.system-update",
|
||||
"omarchy.indicators"
|
||||
]
|
||||
' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null
|
||||
pass "update placement migration moves update after weather"
|
||||
|
||||
jq -e '
|
||||
.bar.layout.center[1].refreshMinutes == 30 and
|
||||
.bar.layout.center[2].custom == true and
|
||||
.bar.layout.center[3].items == ["Dnd", "NightLight"] and
|
||||
.plugins == [{ "id": "custom.plugin", "enabled": true }]
|
||||
' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null
|
||||
pass "update placement migration preserves unrelated settings"
|
||||
|
||||
before=$(sha256sum "$TMPDIR/home/.config/omarchy/shell.json" | awk '{print $1}')
|
||||
HOME="$TMPDIR/home" bash "$migration"
|
||||
after=$(sha256sum "$TMPDIR/home/.config/omarchy/shell.json" | awk '{print $1}')
|
||||
[[ $before == "$after" ]] || fail "update placement migration is idempotent"
|
||||
pass "update placement migration is idempotent"
|
||||
|
||||
clock_migration=$(grep -rl 'Remove leading zero from bar clock date' "$ROOT/migrations" | head -n 1 || true)
|
||||
[[ -n $clock_migration ]] || fail "clock date format migration exists"
|
||||
|
||||
cat >"$TMPDIR/home/.config/omarchy/shell.json" <<'JSON'
|
||||
{
|
||||
"version": 1,
|
||||
"bar": {
|
||||
"layout": {
|
||||
"left": [],
|
||||
"center": [
|
||||
{ "id": "omarchy.clock", "formatAlt": "dd MMMM 'W'ww yyyy" },
|
||||
{ "id": "omarchy.weather" }
|
||||
],
|
||||
"right": [
|
||||
{ "id": "local.clock", "formatAlt": "dd MMMM 'W'ww yyyy" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"plugins": []
|
||||
}
|
||||
JSON
|
||||
|
||||
HOME="$TMPDIR/home" bash "$clock_migration"
|
||||
|
||||
jq -e '
|
||||
.bar.layout.center[0].formatAlt == "d MMMM \u0027W\u0027ww yyyy" and
|
||||
.bar.layout.right[0].formatAlt == "dd MMMM \u0027W\u0027ww yyyy"
|
||||
' "$TMPDIR/home/.config/omarchy/shell.json" >/dev/null
|
||||
pass "clock date format migration removes leading zero from clock"
|
||||
|
||||
before=$(sha256sum "$TMPDIR/home/.config/omarchy/shell.json" | awk '{print $1}')
|
||||
HOME="$TMPDIR/home" bash "$clock_migration"
|
||||
after=$(sha256sum "$TMPDIR/home/.config/omarchy/shell.json" | awk '{print $1}')
|
||||
[[ $before == "$after" ]] || fail "clock date format migration is idempotent"
|
||||
pass "clock date format migration is idempotent"
|
||||
mapfile -t migrations < <(find "$ROOT/migrations" -maxdepth 1 -type f -name '*.sh' -printf '%f\n' | sort)
|
||||
[[ ${#migrations[@]} -eq 1 && ${migrations[0]} == "1780000000_4_0.sh" ]] || fail "historical migrations are collapsed"
|
||||
pass "historical migrations are collapsed into the 4.0 migration"
|
||||
|
||||
@@ -13,6 +13,7 @@ cleanup() {
|
||||
wait "$QS_PID" 2>/dev/null || true
|
||||
fi
|
||||
[[ -n $TMPDIR && -d $TMPDIR ]] && rm -rf "$TMPDIR"
|
||||
return 0
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
|
||||
Reference in New Issue
Block a user