diff --git a/configs/airootfs/usr/share/omarchy-iso/orchestrator/main.py b/configs/airootfs/usr/share/omarchy-iso/orchestrator/main.py index ca53878..fa33ac8 100644 --- a/configs/airootfs/usr/share/omarchy-iso/orchestrator/main.py +++ b/configs/airootfs/usr/share/omarchy-iso/orchestrator/main.py @@ -66,17 +66,22 @@ def main(argv=None) -> int: info(f"Installing Omarchy for {ctx.username} → {ctx.target}") - try: - run(ctx, build_phases()) - except PhaseError: - error("Installation halted.") - return 1 - except KeyboardInterrupt: - error("Installation interrupted.") - return 130 + from .phases_impl import cleanup_bind_mounts - info("Installation complete.") - return 0 + try: + try: + run(ctx, build_phases()) + except PhaseError: + error("Installation halted.") + return 1 + except KeyboardInterrupt: + error("Installation interrupted.") + return 130 + + info("Installation complete.") + return 0 + finally: + cleanup_bind_mounts(ctx) if __name__ == "__main__": 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 0b2ea5e..5b5bc61 100644 --- a/configs/airootfs/usr/share/omarchy-iso/orchestrator/phases_impl.py +++ b/configs/airootfs/usr/share/omarchy-iso/orchestrator/phases_impl.py @@ -359,13 +359,21 @@ def validate_boot(ctx: InstallContext) -> None: # ───────────────────────────────────────────────────────────────────────────── -# finish: unwind bind mounts, prompt for reboot. +# cleanup_bind_mounts: invoked from main()'s finally so bind mounts get +# unwound on success, failure, or interrupt. Idempotent. +# ───────────────────────────────────────────────────────────────────────────── + +def cleanup_bind_mounts(ctx: InstallContext) -> None: + for mount_point in ctx.state.get("bind_mounts", []): + subprocess.run(["umount", mount_point], check=False, capture_output=True) + ctx.state["bind_mounts"] = [] + + +# ───────────────────────────────────────────────────────────────────────────── +# finish: prompt for reboot. Bind mounts are unwound in main()'s finally. # ───────────────────────────────────────────────────────────────────────────── def finish(ctx: InstallContext) -> None: - for mount_point in ctx.state.get("bind_mounts", []): - subprocess.run(["umount", mount_point], check=False, capture_output=True) - info("Installation finished. Reboot when ready.") if confirm("Reboot now?", default=True): os.system("reboot")