#![doc = doc_self!()]
use std::sync::LazyLock;
use async_trait::async_trait;
use indoc::indoc;
use tap::prelude::*;
use super::{DryRunStrategy, NoCacheStrategy, Pm, PmHelper, PmMode, PromptStrategy, Strategy};
use crate::{
config::Config,
error::Result,
exec::{self, Cmd},
};
macro_rules! doc_self {
() => {
indoc! {"
The [Zypper Package Manager](https://en.opensuse.org/Portal:Zypper).
"}
};
}
use doc_self;
#[doc = doc_self!()]
#[derive(Debug)]
pub struct Zypper {
cfg: Config,
}
static STRAT_CHECK_DRY: LazyLock<Strategy> = LazyLock::new(|| Strategy {
dry_run: DryRunStrategy::with_flags(["--dry-run"]),
..Strategy::default()
});
static STRAT_PROMPT: LazyLock<Strategy> = LazyLock::new(|| Strategy {
prompt: PromptStrategy::native_no_confirm(["-y"]),
dry_run: DryRunStrategy::with_flags(["--dry-run"]),
..Strategy::default()
});
static STRAT_INSTALL: LazyLock<Strategy> = LazyLock::new(|| Strategy {
prompt: PromptStrategy::native_no_confirm(["-y"]),
no_cache: NoCacheStrategy::Scc,
dry_run: DryRunStrategy::with_flags(["--dry-run"]),
});
impl Zypper {
#[must_use]
#[allow(missing_docs)]
pub const fn new(cfg: Config) -> Self {
Self { cfg }
}
async fn check_dry(&self, cmd: Cmd) -> Result<()> {
self.run_with(cmd, self.default_mode(), &STRAT_CHECK_DRY)
.await
}
}
#[async_trait]
impl Pm for Zypper {
fn name(&self) -> &'static str {
"zypper"
}
fn cfg(&self) -> &Config {
&self.cfg
}
async fn q(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
if kws.is_empty() {
Cmd::new(["rpm", "-qa", "--qf", "%{NAME} %{VERSION}\\n"])
.flags(flags)
.pipe(|cmd| self.run(cmd))
.await
} else {
self.qs(kws, flags).await
}
}
async fn qc(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
Cmd::new(["rpm", "-q", "--changelog"])
.kws(kws)
.flags(flags)
.pipe(|cmd| self.run(cmd))
.await
}
async fn qi(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
self.si(kws, flags).await
}
async fn ql(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
self.run(Cmd::new(["rpm", "-ql"]).kws(kws).flags(flags))
.await
}
async fn qm(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
let cmd = Cmd::new(["zypper", "search", "-si"]).kws(kws).flags(flags);
let out_bytes = self
.check_output(cmd, PmMode::Mute, &Strategy::default())
.await?;
let out = String::from_utf8(out_bytes)?;
exec::grep_print(&out, &["System Packages"])?;
Ok(())
}
async fn qo(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
self.run(Cmd::new(["rpm", "-qf"]).kws(kws).flags(flags))
.await
}
async fn qp(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
self.run(Cmd::new(["rpm", "-qip"]).kws(kws).flags(flags))
.await
}
async fn qs(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
Cmd::new(["zypper", "search", "--installed-only"])
.kws(kws)
.flags(flags)
.pipe(|cmd| self.check_dry(cmd))
.await
}
async fn qu(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
self.check_dry(Cmd::new(["zypper", "list-updates"]).kws(kws).flags(flags))
.await
}
async fn r(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
Cmd::with_sudo(["zypper", "remove"])
.kws(kws)
.flags(flags)
.pipe(|cmd| self.run_with(cmd, self.default_mode(), &STRAT_PROMPT))
.await
}
async fn rss(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
Cmd::with_sudo(["zypper", "remove", "--clean-deps"])
.kws(kws)
.flags(flags)
.pipe(|cmd| self.run_with(cmd, self.default_mode(), &STRAT_PROMPT))
.await
}
async fn s(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
Cmd::with_sudo(["zypper", "install"])
.kws(kws)
.flags(flags)
.pipe(|cmd| self.run_with(cmd, self.default_mode(), &STRAT_INSTALL))
.await
}
async fn sc(&self, _kws: &[&str], flags: &[&str]) -> Result<()> {
let strat = Strategy {
prompt: PromptStrategy::CustomPrompt,
..Strategy::default()
};
Cmd::with_sudo(["zypper", "clean"])
.flags(flags)
.pipe(|cmd| self.run_with(cmd, self.default_mode(), &strat))
.await
}
async fn scc(&self, _kws: &[&str], flags: &[&str]) -> Result<()> {
self.sc(_kws, flags).await
}
async fn sg(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
Cmd::new(if kws.is_empty() {
["zypper", "patterns"]
} else {
["zypper", "info"]
})
.kws(kws)
.flags(flags)
.pipe(|cmd| self.run(cmd))
.await
}
async fn si(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
Cmd::new(["zypper", "info", "--requires"])
.kws(kws)
.flags(flags)
.pipe(|cmd| self.check_dry(cmd))
.await
}
async fn sl(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
let cmd = &["zypper", "packages", "-R"];
if kws.is_empty() {
let cmd = Cmd::new(cmd).kws(kws).flags(flags);
return self.check_dry(cmd).await;
}
let cmd = Cmd::new(cmd).flags(flags);
let out = self
.check_output(cmd, PmMode::Mute, &STRAT_CHECK_DRY)
.await?
.pipe(String::from_utf8)?;
exec::grep_print_with_header(&out, kws, 4)
}
async fn ss(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
self.check_dry(Cmd::new(["zypper", "search"]).kws(kws).flags(flags))
.await
}
async fn su(&self, _kws: &[&str], flags: &[&str]) -> Result<()> {
Cmd::with_sudo(["zypper", "--no-refresh", "dist-upgrade"])
.flags(flags)
.pipe(|cmd| self.run_with(cmd, self.default_mode(), &STRAT_INSTALL))
.await
}
async fn suy(&self, _kws: &[&str], flags: &[&str]) -> Result<()> {
Cmd::with_sudo(["zypper", "dist-upgrade"])
.flags(flags)
.pipe(|cmd| self.run_with(cmd, self.default_mode(), &STRAT_INSTALL))
.await
}
async fn sw(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
Cmd::with_sudo(["zypper", "install", "--download-only"])
.kws(kws)
.flags(flags)
.pipe(|cmd| self.run_with(cmd, self.default_mode(), &STRAT_INSTALL))
.await
}
async fn sy(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
self.check_dry(Cmd::with_sudo(["zypper", "refresh"]).flags(flags))
.await?;
if !kws.is_empty() {
self.s(kws, flags).await?;
}
Ok(())
}
async fn u(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
self.s(kws, flags).await
}
}