mise 使用 dnf 管理 Red Hat 系 Linux 系统包:[bootstrap.packages] 完整实践指南
【免费下载链接】misedev tools, env vars, task runner项目地址: https://gitcode.com/GitHub_Trending/mi/mise
本篇技术指南围绕 mise 的[bootstrap.packages]配置节与dnf系统包管理器展开,适用于 Fedora、RHEL、CentOS Stream、Rocky Linux、AlmaLinux 等 Red Hat 家族发行版。你将掌握如何用"dnf:包名" = "版本"声明宿主级系统包(原生库、构建依赖、服务端软件),通过mise bootstrap packages status / apply / upgrade完成只读状态检查、预览与幂等安装,并理解版本固定(version pin)、sudo 提权、--refresh元数据刷新等底层行为在源码中的实现方式。读完即可把 mise 当作跨平台、声明式的系统包管理入口,与项目级[tools]形成互补。
一、dnf 管理器:mise 中的 Red Hat 家族包入口
mise 的 bootstrap 系统内置了多个宿主包管理器(apk、apt、aur、brew、dnf、flatpak、pacman、winget 等),它们全部注册在 src/system/packages/mod.rs 的builtin_managers()中,dnf对应DnfManager,其实现位于 src/system/packages/dnf.rs。
dnf管理器专门服务于 Red Hat 家族发行版(Fedora、RHEL、CentOS Stream、Rocky、Alma)。从源码 src/system/packages/dnf.rs 看,它的可用性检查非常直白:
- 必须运行在 Linux 上(
cfg!(target_os = "linux")); - 主机
PATH中必须能找到dnf可执行文件(crate::file::which("dnf"))。
两条不满足时,is_available()返回 false,对应的unavailable_reason()分别给出"only available on linux"或"dnf not found"。这意味着:同一份跨平台共享的配置里写着"dnf:openssl-devel" = "latest",在 Ubuntu 或 macOS 上会被静默跳过(status 命令仍会列出该管理器并标注原因,不会悄悄隐藏),这正是 docs/bootstrap/packages/index.md 中「OS-filtered」语义的体现。
注意:mise 只支持
dnf,不支持仅提供旧版yum的系统。RHEL/CentOS 8+ 以及所有当前 Fedora 发行版均以dnf为默认包管理器,满足此前提。
二、在配置中声明 dnf 系统包
2.1 基础键值形式
在mise.toml(全局~/.config/mise/config.toml或项目级)中写入[bootstrap.packages]节,每条目键为"manager:package",值为版本。dnf 的示例如下(取自 docs/bootstrap/packages/dnf.md):
[bootstrap.packages] "dnf:openssl-devel" = "latest" "dnf:postgresql-server" = "latest" "dnf:bash" = "5.2.26-3.fc40" # 版本或 版本-发行版 固定要点:
- 管理器前缀
dnf:是必需的,mise 依据此前缀把包路由给DnfManager。 - 值为
"latest"时表示「安装该管理器当前提供的版本」。它接受已安装的包,即不会在每次 apply 时反复触发升级;想要更新请显式执行mise bootstrap packages upgrade。 - 值也可以是版本固定(pin),dnf 管理器会把约束原样传给 dnf,语法为 dnf 原生的
name-version/name-version-release。
2.2 表格形式与 OS 过滤
除了键值形式,还可以用表格形式按操作系统限制单个包,os接受单个值或列表,命名与[tools]一致(linux、macos、windows、linux/x64、macos/arm64等):
[bootstrap.packages] "dnf:gcc" = { os = "linux" } "dnf:git" = "latest"省略version时默认"latest"。借助 OS 过滤,一份共享配置可以同时服务多平台主机,dnf 条目只在 Red Hat 系 Linux 上生效。
2.3 与项目级 [tools] 的分工
从 docs/bootstrap/packages/index.md 的「Host packages or mise tools」一节可知,[bootstrap.packages]管理的软件是宿主共享、不随目录切换的,mise 也不会为其创建 shim;而[tools]管理的是每个项目隔离、可版本固定的开发工具。因此:
- 原生库、编译依赖、宿主服务软件(如
openssl-devel、postgresql-server)→[bootstrap.packages]; - 需要按项目切换版本的开发工具 →
[tools]。
三、预览与应用:dnf 包的操作命令
原文档给出三条核心命令,全部作用于当前生效的[bootstrap.packages]声明:
mise bootstrap packages status mise bootstrap packages apply --manager dnf --dry-run mise bootstrap packages apply --manager dnf3.1 status:只读巡检
mise bootstrap packages status(别名ls)输出表格,列包括 Manager、Package、Installed、State。dnf 管理器在 status 阶段会调用rpm -q查询安装状态(见第四节),因此整个过程只读、绝不提权。
常用变体:
mise bootstrap packages status --json # 机器可读输出 mise bootstrap packages status --missing # 存在 drift(如包缺失/版本不匹配)时以退出码 1 结束从 src/cli/system/status.rs 的源码看,--missing只改变退出码而不改变列表内容;--json输出按管理器分组的 JSON,包含available、每个包的requested_version、desired_state、state(如missing、version_mismatch、installed)和installed_version。若管理器不可用,对应包会被标记为skipped并附原因。
3.2 apply:安装缺失包
mise bootstrap packages apply(别名install/i,对应 src/cli/system/install.rs)会先检查哪些声明包缺失,再调用管理器安装。--manager dnf将本次操作限定在 dnf 管理器:
mise bootstrap packages apply --manager dnf --dry-run # 打印将要执行的 dnf 命令,不实际安装 mise bootstrap packages apply --manager dnf # 实际安装(可能触发 sudo 确认) mise bootstrap packages apply --manager dnf --yes # 跳过 mise 的确认提示 mise bootstrap packages apply --update # 安装前刷新元数据(dnf 对应 --refresh)要点:
- 不传包参数时读取当前配置;也可显式传包,如
mise bootstrap packages apply dnf:openssl-devel,此时只安装不写入配置。 --manager dnf在主机不可用时会直接失败(驱动层设置allow_unavailable_manager: false),这正是原文档强调的「管理器必须存在于主机上」。--yes只跳过 mise 自己的确认提示,不提供 sudo 凭据。
3.3 use:声明并安装一步到位
mise bootstrap packages use dnf:openssl-develmise bootstrap packages use(src/cli/bootstrap.rs 中注册为Use子命令)等价于系统包版的mise use:把"dnf:openssl-devel" = "latest"写入mise.toml(本地文件;-g写全局),并立即安装缺失部分。若当前主机上该管理器不可用,条目照样写入但不安装——这正是跨平台共享配置能够在 macOS 上留下dnf:行的原因。
3.4 upgrade:升级已安装的包
mise bootstrap packages upgrade --manager dnf mise bootstrap packages upgrade --manager dnf --dry-run从 src/cli/system/upgrade.rs 的说明看,upgrade 会刷新包管理器元数据,并只升级已安装的配置包(缺失的包被跳过,那是 apply 的职责)。对 dnf 而言,实际执行的是dnf upgrade -y --refresh,且会遵守配置中的版本固定。
3.5 命令速查
| 命令 | 作用 | dnf 底层动作 |
|---|---|---|
mise bootstrap packages status | 只读状态巡检 | rpm -q --qf "%{NAME}\t%{VERSION}-%{RELEASE}\n" ... |
mise bootstrap packages apply --manager dnf --dry-run | 预览将执行的命令 | 打印dnf install -y ...(含可能的 sudo 前缀) |
mise bootstrap packages apply --manager dnf | 安装缺失/不匹配的包 | dnf install -y [--refresh] <operand>... |
mise bootstrap packages apply --update | 安装前强制刷新元数据 | 追加--refresh |
mise bootstrap packages use dnf:xxx | 写入配置并安装 | 同上 |
mise bootstrap packages upgrade --manager dnf | 升级已安装的包 | dnf upgrade -y --refresh <operand>... |
四、行为细节:从源码看 dnf 管理器如何工作
原文档的 Behavior 小节描述了四条行为,这里结合 src/system/packages/dnf.rs 逐条展开。
4.1 状态检查:只读的 rpm -q
DnfManager::installed()(src/system/packages/dnf.rs)执行:
rpm -q --qf "%{NAME}\t%{VERSION}-%{RELEASE}\n" <name>...输出按名称\t版本-发行版逐行解析(parse_rpm_query,src/system/packages/dnf.rs)。该命令只读、绝不提权(installed的 trait 契约即要求「side-effect free and never elevate」)。rpm -q在包缺失时返回非零,但输出中package X is not installed会被识别并忽略,缺失的包最终解析为PackageState::Missing;只有与「未安装」无关的 rpm 错误才会导致失败。
4.2 安装:dnf install -y + sudo 提权
install_args()(src/system/packages/dnf.rs)构造的命令为:
dnf install -y [--refresh] <operand>...install()(src/system/packages/dnf.rs)经sudo::run("dnf", &args, &[])执行;--dry-run时则打印sudo::argv("dnf", &args)拼出的完整命令行。sudo 的触发策略见第六节。注意源码中有一处关键注释:永远不会在参数里追加裸--,因为 DNF5 在install/upgrade等子命令上会拒绝裸--;而版本固定用的是 rpm NEVRA 语法(name-version),dnf 以位置参数直接接受。
4.3 版本固定如何传给 dnf
pkg_operand()(src/system/packages/dnf.rs)把PackageRequest渲染为 dnf 原生操作数:
- 无版本:仅包名,如
openssl-devel; - 有版本:
name-version,如bash-5.2.26-3.fc40。
而版本匹配逻辑在parse_rpm_query中:版本-发行版固定(如5.2.26-3.fc40)必须与已安装的VERSION-RELEASE完全相等;仅版本固定(如3.4)则匹配任意发行版(version.starts_with("3.4-"))。不满足时状态为PackageState::VersionMismatch,并记录已安装版本。这一点被 src/system/packages/dnf.rs 的单元测试覆盖,例如已装tmux 3.4-3.fc40满足"tmux" = "3.4",而已装zsh 5.9-2.fc40不满足"zsh" = "5.8-1.fc40";另外已装的glib2也绝不会满足glib2-devel的请求(包名必须精确匹配)。
4.4 --update 与 --refresh
mise bootstrap packages apply --update会给 dnf 的 install 命令追加--refresh(InstallOpts.update为 true 时,src/system/packages/dnf.rs),强制过期并刷新仓库元数据;不加该标志时,dnf 自行管理元数据过期策略。源码测试test_install_args_update_adds_refresh断言了参数顺序:["install", "-y", "--refresh", "ripgrep"]。
4.5 upgrade 的语义
upgrade_args()(src/system/packages/dnf.rs)固定构造:
dnf upgrade -y --refresh <operand>...注释解释了为什么总是带--refresh:过期的元数据会让upgrade变成「静默空操作」。dnf upgrade <pkg>只触碰已安装的包;若配置的 pin 需要降级,走 install 路径的dnf install name-version即可(这正是 install 与 upgrade 分工的边界)。
五、版本选择与可移植性
原文档强调:"dnf:bash" = "5.2.26-3.fc40"这样的 Fedora 版本-发行版字符串只用于演示语法,不可跨发行版或跨发行版版本移植。选择版本时必须确认目标系统启用仓库中存在该版本:
- mise 只是把约束原样转交给 dnf,不会自行添加仓库、也不会去取回存档 RPM 来满足约束;
"latest"接受已安装的包,想要更新需用upgrade;- 源码包与原生依赖解析依旧是 dnf 的职责,mise 不介入。
因此推荐做法是:共享配置里写"latest"或宽松的仅版本 pin,把精确的version-release留给单一发行版专用的配置(可配合os过滤与平台配置文件使用)。
六、sudo 提权策略
dnf 与 apk、apt、pacman 一样,变更包时需要 root,mise 通过统一的 sudo 路径处理(docs/bootstrap/packages/index.md 的「sudo」一节):
- 已是 root(容器、CI):不使用 sudo,命令直接执行;
- 交互终端:执行
sudo dnf install -y ...,出现正常 sudo 密码提示; - 非交互且无免密 sudo:mise 报错并打印需要手动执行的完整命令,绝不挂起等待密码;
- 任何情况下,完整命令行在执行前都会被记录日志。
若希望完全禁止提权,可设置system_packages.sudo = false(对应配置项见 docs/configuration/settings.md),此时 mise 只打印命令由你自行运行。另外注意:包插件(package plugins)永远不会走 mise 的 sudo 路径,也绝不允许自行提权,但内置的 dnf 管理器不在此列。
七、CI 场景:一条命令装齐宿主依赖
在容器里通常已是 root,不会出现任何提示,可以这样做(来自 docs/bootstrap/packages/index.md 的 CI 用法):
mise bootstrap packages apply --yes mise installmise bootstrap --yes则把两者合并(之后若定义了名为bootstrap的任务还会执行它)——一条命令完成新机器/容器的初始化。CI 巡检还可以用:
mise bootstrap packages status --missing # 存在缺失/漂移时退出码为 1注意:status会把不可用管理器上的声明标记为skipped,因此「跳过」并不能证明包已安装,需要时请配合--json检查。
八、本文依据的仓库资源
- 核心文档:docs/bootstrap/packages/dnf.md(RPM/dnf 说明)
- 通用语义与 sudo/CI 细节:docs/bootstrap/packages/index.md
- dnf 管理器实现:src/system/packages/dnf.rs
- 管理器抽象与注册:src/system/packages/mod.rs
- CLI 命令定义:src/cli/bootstrap.rs、src/cli/system/install.rs、src/cli/system/upgrade.rs、src/cli/system/status.rs
小结
mise 通过DnfManager把 Red Hat 系发行版的系统包纳入声明式配置:rpm -q只读巡检、dnf install -y(必要时 sudo)收敛状态、dnf upgrade -y --refresh完成升级、name-version/name-version-release原样透传版本固定,且全程遵循「手动安装、绝不隐式提权、跨平台静默跳过」的设计原则。把宿主依赖交给[bootstrap.packages],把项目工具交给[tools],即可获得一套清晰、可复现、可跨平台共享的开发环境初始化流程。
【免费下载链接】misedev tools, env vars, task runner项目地址: https://gitcode.com/GitHub_Trending/mi/mise
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考