mise 使用 dnf 管理 Red Hat 系 Linux 系统包:[bootstrap.packages] 完整实践指南
2026/9/10 15:26:14 网站建设 项目流程

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]一致(linuxmacoswindowslinux/x64macos/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-develpostgresql-server)→[bootstrap.packages]
  • 需要按项目切换版本的开发工具 →[tools]

三、预览与应用:dnf 包的操作命令

原文档给出三条核心命令,全部作用于当前生效的[bootstrap.packages]声明:

mise bootstrap packages status mise bootstrap packages apply --manager dnf --dry-run mise bootstrap packages apply --manager dnf

3.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_versiondesired_statestate(如missingversion_mismatchinstalled)和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-devel

mise 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 命令追加--refreshInstallOpts.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 install

mise 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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询