installer: unify finalizer logging
This commit is contained in:
4 files changed
+67
-14
No files matched your search
@@ -94,9 +94,13 @@ cat >"$fail_worker" <<EOF
|
||||
set -euo pipefail
|
||||
state="\$1"
|
||||
mkdir -p "\$(dirname "\$state")"
|
||||
python - "\$state" "Installing Arch + Omarchy" <<'PY'
|
||||
python - "\$state" "Finalizing in chroot" <<'PY'
|
||||
$write_state_py
|
||||
PY
|
||||
echo "Syncing the system..."
|
||||
echo "Installation completed without any errors."
|
||||
printf '\033[?25h'
|
||||
echo "You may reboot when ready."
|
||||
sleep 0.2
|
||||
exit 7
|
||||
EOF
|
||||
@@ -132,8 +136,15 @@ if [[ $fail_status -ne 7 ]]; then
|
||||
echo "Expected failure worker status 7, got $fail_status" >&2
|
||||
exit 1
|
||||
fi
|
||||
assert_contains "$fail_log" "Installation completed without any errors."
|
||||
assert_contains "$fail_log" "[dashboard] installer child exited with status 7"
|
||||
assert_contains "$fail_log" "[dashboard] last installer phase: Installing Arch + Omarchy"
|
||||
assert_contains "$fail_log" "[dashboard] last installer phase: Finalizing in chroot"
|
||||
python - "$fail_log" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
if "\x1b[?25h" in Path(sys.argv[1]).read_text(errors="ignore"):
|
||||
raise SystemExit("CSI cursor sequence leaked into log")
|
||||
PY
|
||||
assert_not_contains "$fail_capture" "Installed in"
|
||||
assert_not_contains "$fail_capture" "Finished installing"
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ touch "$OMARCHY_INSTALL_LOG_FILE"
|
||||
|
||||
export COLUMNS=$(tput cols)
|
||||
export LINES=$(tput lines)
|
||||
exec > >(tee >(sed -u 's/\x1b\[[0-9;]*[a-zA-Z]//g' >>"$OMARCHY_INSTALL_LOG_FILE") 2>/dev/null) 2>/dev/tty
|
||||
exec > >(tee >(sed -u 's/\x1b\[[0-9;?]*[A-Za-z]//g' >>"$OMARCHY_INSTALL_LOG_FILE") 2>/dev/null) 2>/dev/tty
|
||||
export CLICOLOR_FORCE=1
|
||||
export FORCE_COLOR=1
|
||||
|
||||
|
||||
@@ -60,6 +60,10 @@ cleanup() {
|
||||
printf '%s%s' "$RESET" "$SHOW_CURSOR" >"$TTY_PATH" 2>/dev/null || true
|
||||
}
|
||||
|
||||
dashboard_log() {
|
||||
printf '[dashboard] %s\n' "$*" >>"$LOG_FILE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
stop_child() {
|
||||
[[ -n ${child_pid:-} ]] || return 0
|
||||
if kill -0 "$child_pid" 2>/dev/null; then
|
||||
@@ -308,7 +312,7 @@ reboot_prompt() {
|
||||
launch_child() {
|
||||
mkdir -p "$(dirname "$LOG_FILE")"
|
||||
# Child is non-interactive. All visible UI belongs to this supervisor.
|
||||
setsid "${INSTALL_CMD[@]}" </dev/null > >(sed -u 's/\x1b\[[0-9;]*[a-zA-Z]//g' >>"$LOG_FILE") 2>&1 &
|
||||
setsid "${INSTALL_CMD[@]}" </dev/null > >(sed -u 's/\x1b\[[0-9;?]*[A-Za-z]//g' >>"$LOG_FILE") 2>&1 &
|
||||
child_pid=$!
|
||||
child_pgid=$child_pid
|
||||
}
|
||||
@@ -320,7 +324,7 @@ launch_child
|
||||
|
||||
frame=0
|
||||
while jobs -pr | grep -qx "$child_pid"; do
|
||||
render_dynamic "$frame" >"$TTY_PATH"
|
||||
render_dynamic "$frame" >"$TTY_PATH" 2>/dev/null || true
|
||||
frame=$((frame + 1))
|
||||
sleep 0.5
|
||||
done
|
||||
@@ -332,11 +336,11 @@ set -e
|
||||
child_pid=""
|
||||
child_pgid=""
|
||||
|
||||
echo "[dashboard] installer child exited with status $status" >>"$LOG_FILE"
|
||||
dashboard_log "installer child exited with status $status"
|
||||
|
||||
if (( status != 0 )); then
|
||||
if [[ -f $STATE_FILE ]]; then
|
||||
python - "$STATE_FILE" >>"$LOG_FILE" <<'PY' 2>/dev/null || true
|
||||
state_summary="$(python - "$STATE_FILE" <<'PY' 2>/dev/null || true
|
||||
import json, sys
|
||||
try:
|
||||
state = json.load(open(sys.argv[1]))
|
||||
@@ -344,10 +348,20 @@ except Exception:
|
||||
raise SystemExit(0)
|
||||
phase = state.get("current_phase")
|
||||
if phase:
|
||||
print(f"[dashboard] last installer phase: {phase}")
|
||||
print(f"last installer phase: {phase}")
|
||||
for item in reversed(state.get("phases", [])):
|
||||
if item.get("status") == "failed":
|
||||
print(f"failed phase: {item.get('name')}: {item.get('error')}")
|
||||
break
|
||||
PY
|
||||
)"
|
||||
if [[ -n ${state_summary:-} ]]; then
|
||||
while IFS= read -r line; do
|
||||
[[ -n $line ]] && dashboard_log "$line"
|
||||
done <<<"$state_summary"
|
||||
fi
|
||||
fi
|
||||
printf '%s%s' "$SHOW_CURSOR" "$CLEAR" >"$TTY_PATH"
|
||||
printf '%s%s' "$SHOW_CURSOR" "$CLEAR" >"$TTY_PATH" 2>/dev/null || true
|
||||
exit "$status"
|
||||
fi
|
||||
|
||||
@@ -356,7 +370,7 @@ render_finish
|
||||
finish_render_status=$?
|
||||
set -e
|
||||
if (( finish_render_status != 0 )); then
|
||||
echo "[dashboard] finish screen render failed with status $finish_render_status; using fallback" >>"$LOG_FILE"
|
||||
dashboard_log "finish screen render failed with status $finish_render_status; using fallback"
|
||||
{
|
||||
printf '%s%s' "$SHOW_CURSOR" "$CLEAR"
|
||||
printf '\nFinished installing\n\n'
|
||||
@@ -368,7 +382,7 @@ if [[ ${OMARCHY_UI_AUTO_REBOOT:-} == "no" ]]; then
|
||||
fi
|
||||
|
||||
if reboot_prompt; then
|
||||
printf '%s' "$CLEAR" >"$TTY_PATH"
|
||||
printf '%s' "$CLEAR" >"$TTY_PATH" 2>/dev/null || true
|
||||
reboot 2>/dev/null || systemctl reboot 2>/dev/null || true
|
||||
fi
|
||||
|
||||
|
||||
@@ -827,14 +827,28 @@ def run_chroot_finalizer(ctx: InstallContext) -> None:
|
||||
)
|
||||
sudoers.chmod(0o440)
|
||||
|
||||
# run_logged appends as the install user. Create the target log before
|
||||
# arch-chroot so the first redirection cannot fail on /var/log perms.
|
||||
# run_logged appends as the install user. Bind the target's
|
||||
# /var/log/omarchy-install.log to the live ISO log so the error UI, upload,
|
||||
# and "view full log" all show the finalizer details instead of a separate
|
||||
# hidden target-only log.
|
||||
target_log = ctx.target / "var" / "log" / "omarchy-install.log"
|
||||
omarchy_start_epoch = int(time.time())
|
||||
omarchy_start_time = time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
ctx.log_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
ctx.log_path.touch(exist_ok=True)
|
||||
ctx.log_path.chmod(0o666)
|
||||
target_log.parent.mkdir(parents=True, exist_ok=True)
|
||||
target_log.write_text(f"=== Omarchy Installation Started: {omarchy_start_time} ===\n")
|
||||
target_log.touch(exist_ok=True)
|
||||
target_log.chmod(0o666)
|
||||
with ctx.log_path.open("a", encoding="utf-8") as log:
|
||||
log.write(f"=== Omarchy Finalizer Started: {omarchy_start_time} ===\n")
|
||||
log_bind_mounted = False
|
||||
try:
|
||||
subprocess.run(["mount", "--bind", str(ctx.log_path), str(target_log)], check=True)
|
||||
log_bind_mounted = True
|
||||
except subprocess.CalledProcessError as exc:
|
||||
with ctx.log_path.open("a", encoding="utf-8") as log:
|
||||
log.write(f"[orchestrator] WARNING: failed to bind unified finalizer log: {exc}\n")
|
||||
|
||||
# 4: copy install tooling somewhere arch-chroot will not mask. /tmp is not
|
||||
# safe here: arch-chroot mounts a fresh tmpfs over the target's /tmp before
|
||||
@@ -892,6 +906,20 @@ def run_chroot_finalizer(ctx: InstallContext) -> None:
|
||||
subprocess.run(cmd, check=True)
|
||||
finally:
|
||||
sudoers.unlink(missing_ok=True)
|
||||
if log_bind_mounted:
|
||||
subprocess.run(["umount", str(target_log)], check=False, capture_output=True)
|
||||
try:
|
||||
shutil.copy2(ctx.log_path, target_log)
|
||||
target_log.chmod(0o644)
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
with ctx.log_path.open("a", encoding="utf-8") as live_log:
|
||||
live_log.write("\n=== Target finalizer log ===\n")
|
||||
live_log.write(target_log.read_text(errors="ignore"))
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def _read_omarchy_mirror() -> str:
|
||||
|
||||
Reference in new issue
Block a user