跳转至

03 · 安装、引导与首登

Quattro 不把安装写成一个“万能 root 脚本”。它把必须 root 的系统副作用、必须知道 owner 的 home 操作,以及必须进入图形会话的动作分成三个关卡。

为什么不能一次做完

安装时可用的上下文逐步增加:

阶段 已知/可用 尚不可依赖
system apply root、目标磁盘、pacman、systemd system 用户 D-Bus、DConf、通知、音频 session
user finalize owner、HOME、用户文件权限 已运行的 Shell、稳定的图形服务
first run graphical session、user systemd、D-Bus 无需再假装是安装环境

把动作放错阶段会产生经典问题:root 拥有用户文件、systemctl --user 连接不到 bus、音频调优找不到 sink、欢迎通知无处显示。

入口一:omarchy-apply-system

该入口要求 root,接收安装用户与 deferred 模式等参数,建立统一日志和环境,然后按顺序执行三组脚本:

flowchart TD
    Apply[omarchy-apply-system] --> Guard{EUID == 0?}
    Guard -->|否| Stop[拒绝]
    Guard -->|是| Env[参数/环境/日志]
    Env --> Hardware[omarchy-apply-hardware]
    Hardware --> Login[install/login/all.sh]
    Login --> Post[install/post-install/all.sh]
    Env --> Config[install/config/all.sh]

系统配置集合涵盖主题系统准备、登录锁定、PAM、SSH、Docker、Snapper、locate、systemd 服务和防火墙等。硬件集合单独编排,是因为每一项都需要先探测再幂等应用。

编排脚本为何多用 source

顶层安装器把阶段脚本 source 到同一个受控 shell 中,因此它们共享安装上下文、错误策略和 helper。好处是日志与失败传播统一;代价是变量命名需要克制,脚本不能假设独立进程隔离。

入口二:用户 finalizer

omarchy-provision-user 的首要防线是拒绝 root。随后它检查 finalization marker,避免重复完成一次性动作。

~/.local/state/omarchy/done/finalize-user

核心工作包括:

  • 建立 AI agent skills 的用户链接;
  • 修正 XDG user dirs 和 GTK bookmarks;
  • 执行 install/user/all.sh 中的 Git、mise、主题、XCompose 等动作;
  • 刷新 desktop 应用库、默认浏览器与 mailto;
  • 对全新安装,把已有迁移标记为已应用。

最后一项很关键:全新安装得到的包内容已经是当前状态,再执行“从历史版本迁到当前”的脚本既浪费又可能破坏状态。因此 fresh install 创建 migration markers,升级机器则由 migrator 真正运行脚本。

入口三:first-run

first-run marker 与 finalization marker 分开:

~/.local/state/omarchy/done/first-run-user

first-run 会先确保 finalizer 已完成,然后:

  1. 安装或刷新 post-update hooks;
  2. 启用用户级 systemd units;
  3. 应用 GNOME/GTK 相关设置;
  4. 配置初始音频调优;
  5. 等待通知服务可用;
  6. 展示欢迎信息与 Wi-Fi 提示。
sequenceDiagram
    participant G as 图形登录
    participant F as omarchy-first-run
    participant P as provision-user
    participant US as user systemd/D-Bus
    participant Q as Quickshell 通知
    G->>F: 启动 first-run
    F->>P: 确保 finalization
    P-->>F: done
    F->>US: enable units / apply settings
    F->>Q: 等待服务并发送欢迎
    alt 全部成功
      F->>F: 写 first-run marker
    else 任一步失败
      F->>F: 记录错误,不写 marker
    end

marker 是提交记录,不是开始记录

只有所有必需动作成功后才写 marker。若中间失败,下次登录会重试。这里可把 marker 看成一个极简事务提交:它不回滚已成功的幂等动作,但阻止“半完成”被误认为完成。

deferred 模式怎样跨 reboot

当安装过程暂时没有 owner,会留下 pending 状态。首启的 provisioning service 完成 owner 创建和 finalization。与其把未知用户名硬编码进系统镜像,这种方式把决定延迟到拥有足够信息的时刻。

stateDiagram-v2
    [*] --> Deferred: apply-system --deferred
    Deferred --> Pending: 写系统状态
    Pending --> OwnerKnown: 首启 setup/provision
    OwnerKnown --> UserFinalized
    UserFinalized --> GraphicalFirstRun
    GraphicalFirstRun --> Ready

幂等的真实含义

这里的幂等不是“脚本可以无限重复且绝无副作用”,而是三种策略的组合:

  • 状态探测:服务、包、文件是否已经满足目标;
  • marker 跳过:一次性生命周期动作成功后不再进入;
  • 可安全重放:失败前已完成的小步骤再次执行不会造成冲突。

所以排障时不要第一反应删除所有 marker。先看 marker 对应的承诺是否真的成立;migration marker、first-run marker 与普通生成状态有完全不同的语义。

失败观察点

症状 先检查 解释
系统包在但用户配置缺 provisioning pending / finalize marker 可能只完成 root 阶段
用户 unit 没启用 first-run marker 与图形会话日志 不能只看 finalizer
新机运行历史迁移出错 migration markers 是否在 fresh install 创建 新安装应直接视为 current
home 文件归 root 是否绕过 omarchy-provision-user 的用户边界 用户阶段不应 root 执行
欢迎通知不出现 Shell 通知服务是否已就绪 first-run 明确等待图形服务

关键源码索引

机器准备好以后,下一条链从 display manager 进入会话:04 · 会话启动与 Hyprland。