Skip to main content

krypt_pkg/
dnf.rs

1//! `dnf` package manager implementation (Fedora / RHEL).
2
3use crate::manager::{PackageError, PackageManager, RunOutcome, Runner};
4
5/// Package manager implementation for Fedora-family systems.
6pub struct Dnf;
7
8impl PackageManager for Dnf {
9    fn name(&self) -> &'static str {
10        "dnf"
11    }
12
13    fn is_available(&self) -> bool {
14        which::which("dnf").is_ok()
15    }
16
17    /// `dnf repoquery --whatprovides` matches package names, virtual provides
18    /// (Fedora's `nodejs` is provided by `nodejs22`) and file paths, as
19    /// `dnf install` does; it exits 0 with no output when nothing matches. A
20    /// `@group` is looked up with `dnf group info`.
21    fn exists(&self, runner: &dyn Runner, pkg: &str) -> Result<bool, PackageError> {
22        if let Some(group) = pkg.strip_prefix('@') {
23            let RunOutcome { status, .. } = runner.run("dnf", &["group", "info", group])?;
24            return Ok(status == 0);
25        }
26        let RunOutcome { status, stdout, .. } =
27            runner.run("dnf", &["repoquery", "--quiet", "--whatprovides", pkg])?;
28        Ok(status == 0 && !stdout.trim().is_empty())
29    }
30
31    /// `rpm -q --whatprovides`, so a name that another package provides counts
32    /// once `dnf install` has resolved it (Fedora's `wget` is `wget2-wget`).
33    fn is_installed(&self, runner: &dyn Runner, pkg: &str) -> Result<bool, PackageError> {
34        let RunOutcome { status, .. } = runner.run("rpm", &["-q", "--whatprovides", pkg])?;
35        Ok(status == 0)
36    }
37
38    fn install(&self, runner: &dyn Runner, packages: &[String]) -> Result<(), PackageError> {
39        let mut args = vec!["install", "-y"];
40        args.extend(packages.iter().map(String::as_str));
41        let RunOutcome { status, stderr, .. } = runner.run_as_root("dnf", &args)?;
42        if status != 0 {
43            return Err(PackageError::ExitFailure { status, stderr });
44        }
45        Ok(())
46    }
47}