跳转至

18 · 端到端调用链

前面的章节按子系统拆开;这一章反过来,从用户可见动作一路追到状态和失败边界。它适合作为排障入口。

Trace A:第一次启动桌面

sequenceDiagram
    participant P as pacman/installer
    participant A as apply-system(root)
    participant O as provision-owner
    participant F as provision-user
    participant S as SDDM/UWSM
    participant H as Hyprland
    participant Q as Quickshell
    P->>A: 安装 packages + 应用系统
    A->>A: config/hardware/login/post-install
    alt owner 未知
      A->>O: 留 pending,跨 reboot
    end
    O->>F: 以 owner 身份 finalize
    F->>F: user config/default apps/migration markers
    S->>H: 启动 Omarchy Wayland session
    H->>Q: autostart shell
    Q->>Q: registry/services/bar
    H->>F: first-run in graphical session
    F->>Q: 等通知服务,展示 welcome

可观察事实

  • system 阶段:root 日志与 /var/lib/omarchy/provisioning;
  • user 阶段:~/.local/state/omarchy/done/finalize-user;
  • first-run:独立 marker 与 user units;
  • session:/run/user/<uid>/hypr、user systemd environment;
  • Shell:omarchy shell ping。

最常见误诊

“包都装了,所以 first-run 也应该完成。”包状态只能证明磁盘基线,不能证明图形用户服务已运行。

Trace B:omarchy theme set nord

sequenceDiagram
    participant U as 用户
    participant R as bin/omarchy
    participant T as theme-set
    participant FS as state filesystem
    participant Q as Quickshell
    participant A as 外围应用
    U->>R: omarchy theme set nord
    R->>R: 最长前缀找到 omarchy-theme-set
    R->>T: exec nord
    T->>T: 获取锁,验证 source/trust
    T->>FS: 构建 next-theme + templates
    T->>FS: atomic swap current/theme
    T->>Q: applyTheme + wallpaper transition
    T->>A: 并行 retint/restart
    T->>T: theme-set hook

失败定位

  1. 命令没启动:查 router/可执行权限;
  2. 报 busy:查 theme lock 与并发切换;
  3. template 错:current 应仍是旧主题,查 staging/模板;
  4. 文件已变但 Shell 未变:查 omarchy shell ping / applyTheme;
  5. 只有某应用颜色旧:查该应用 post action,而非回滚整个主题。

一致性边界

原子性只覆盖活动主题文件的 swap;外围应用在锁释放后最终一致。理解这个边界可以避免把正常的短暂延迟当作数据损坏。

Trace C:菜单里安装一个应用

sequenceDiagram
    participant U as 用户
    participant M as Menu plugin
    participant G as Guard cache
    participant C as install command
    participant P as pacman/AUR
    participant L as AppLibrary
    U->>M: 打开 Install submenu
    M->>G: 立即显示 cached installed 状态
    M->>G: 后台批量刷新
    U->>M: 选择未安装项
    M->>C: detached action
    C->>P: 探测、安装、验证
    C->>L: 刷新 applications(按命令契约)
    M->>G: 下次 open 看到已安装
    G-->>M: entry disabled + ✓

并发原则

UI guard 可能是旧的;安装命令必须再次探测。反过来,命令成功也不意味着当前已打开菜单瞬间更新,除非触发 refresh。这是缓存与真相的正常分工。

Trace D:更新在第 N 个迁移失败

sequenceDiagram
    participant U as update
    participant S as Snapper
    participant P as pacman
    participant M as migrator
    participant F as migration N
    participant D as marker dir
    U->>S: create snapshot
    U->>P: system package transaction
    P-->>U: success
    U->>M: run pending sorted
    M->>F: bash -euo pipefail
    F-->>M: non-zero
    M--xD: 不写 N marker
    M-->>U: failure,停止后续迁移

机器此刻是什么状态

  • 新 packages 已安装;
  • 早于 N 的迁移 marker 已写;
  • N 可能有部分副作用,但没有 marker;
  • N 之后尚未执行;
  • update 的外围 AUR/mise/restart 可能没执行;
  • update 前 snapshot 存在。

正确恢复顺序

先看 /tmp/omarchy-update.log 找 N 的第一个错误;修复环境或迁移幂等问题;重跑 migrator/update。不要手工 touch marker 来“绕过”,除非已证明 N 的目标状态全部成立。

Trace E:安装并启用第三方插件

flowchart TD
    URL[git URL] --> Confirm[终端警告/确认]
    Confirm --> Clone[clone 到 user plugins]
    Clone --> Validate[manifest/entrypoint/no symlink]
    Validate --> Disabled[落盘但默认禁用]
    Disabled --> Review[用户审代码]
    Review --> Enable[shell.json 写启用/位置]
    Enable --> Rescan[Registry inotify/rescan]
    Rescan --> Load[Qt.createComponent]
    Load --> Host[注入 shell/registry/manifest]

信任发生在哪里

clone 只是下载;enable 才授权执行。对 full bar,若 load 失败回退内置 bar;对普通插件,仍应从 Shell 日志查看加载错误。插件与 Shell 同进程,没有权限沙箱。

Trace F:窗口间距 toggle

sequenceDiagram
    participant K as Hyprland keybind
    participant C as omarchy-hyprland-toggle
    participant St as ~/.local/state
    participant H as Hyprland Lua reload
    K->>C: 切换 gaps flag
    C->>St: 写/删动态 Lua 状态
    C->>H: 请求 reload
    H->>H: bootstrap 清 module cache
    H->>St: state path 优先 require
    H-->>K: 新 layout 生效

如果 reload 后恢复旧值,先查 state 文件是否生成,再查 bootstrap/package.path,而不是先修改用户 looknfeel.lua。toggle 是生成状态,不是长期配置。

Trace G:Factory reset

sequenceDiagram
    participant U as 当前 owner
    participant R as reset stage
    participant B as Boot/UKI
    participant F as early finish service
    participant N as 新 owner provisioning
    U->>R: 输入 reset + 认证
    R->>R: clone @factory / scrub staged root
    R->>B: 重建并验证 UKI hash
    R->>F: arm wipe-pending
    B->>F: reboot 到 staged root
    F->>F: 删除旧 root,重建 @home/@log
    alt 成功
      F->>N: 清 pending,进入 provisioning
    else 失败
      F->>F: 保留 pending,下次 boot 重试
    end

reset 的成功标准不是“当前命令返回 0”,而是下次 boot 的 finish service 完成并清除 wipe marker。跨 boot 操作必须按阶段观察。

用调用链排障的模板

遇到任何新问题,可按以下顺序写下事实:

  1. 入口:谁调用了哪个 omarchy-* / IPC / unit?
  2. 执行身份:root、普通用户还是图形 session?
  3. 上一个提交点:lock、snapshot、atomic swap、marker 或 package transaction?
  4. 目标状态:具体路径、service、QML property 或设备状态?
  5. 下游确认:退出码、日志、IPC response、systemd state、截图?
  6. 安全重放范围:哪一步有 marker,哪一步可能已产生部分副作用?

这比“再跑一次看看”多花一分钟,但通常能避免跨错层修复。

下一章把这些机制提炼为可移植的工程经验:19 · 可复用的设计经验。