1#![doc = doc_self!()]
2
3use std::sync::LazyLock;
4
5use async_trait::async_trait;
6use indoc::indoc;
7use itertools::Itertools;
8use tap::prelude::*;
9
10use super::{NoCacheStrategy, Pm, PmHelper, PromptStrategy, Strategy};
11use crate::{config::Config, error::Result, exec::Cmd};
12
13macro_rules! doc_self {
14 () => {
15 indoc! {"
16 The [Portage Package Manager](https://wiki.gentoo.org/wiki/Portage).
17 "}
18 };
19}
20use doc_self;
21
22#[doc = doc_self!()]
23#[derive(Debug)]
24pub struct Emerge {
25 cfg: Config,
26}
27
28static STRAT_ASK: LazyLock<Strategy> = LazyLock::new(|| Strategy {
29 prompt: PromptStrategy::native_confirm(["--ask"]),
30 ..Strategy::default()
31});
32
33static STRAT_INTERACTIVE: LazyLock<Strategy> = LazyLock::new(|| Strategy {
34 prompt: PromptStrategy::native_confirm(["--interactive"]),
35 ..Strategy::default()
36});
37
38static STRAT_INSTALL: LazyLock<Strategy> = LazyLock::new(|| Strategy {
39 prompt: PromptStrategy::native_confirm(["--ask"]),
40 no_cache: NoCacheStrategy::Scc,
41 ..Strategy::default()
42});
43
44impl Emerge {
45 #[must_use]
46 #[allow(missing_docs)]
47 pub const fn new(cfg: Config) -> Self {
48 Self { cfg }
49 }
50}
51
52#[async_trait]
53impl Pm for Emerge {
54 fn name(&self) -> &'static str {
56 "emerge"
57 }
58
59 fn cfg(&self) -> &Config {
60 &self.cfg
61 }
62
63 async fn q(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
65 self.qs(kws, flags).await
66 }
67
68 async fn qi(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
70 self.si(kws, flags).await
71 }
72
73 async fn ql(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
75 self.run(Cmd::new(["qlist"]).kws(kws).flags(flags)).await
76 }
77
78 async fn qo(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
80 self.run(Cmd::new(["qfile"]).kws(kws).flags(flags)).await
81 }
82
83 async fn qs(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
88 self.run(Cmd::new(["qlist", "-I"]).kws(kws).flags(flags))
89 .await
90 }
91
92 async fn qu(&self, _kws: &[&str], flags: &[&str]) -> Result<()> {
94 self.run(Cmd::new(["emerge", "-uDNp", "@world"]).flags(flags))
95 .await
96 }
97
98 async fn r(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
100 Cmd::with_sudo(["emerge", "--unmerge"])
101 .kws(kws)
102 .flags(flags)
103 .pipe(|cmd| self.run_with(cmd, self.default_mode(), &STRAT_ASK))
104 .await
105 }
106
107 async fn rs(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
110 Cmd::with_sudo(["emerge", "--depclean"])
111 .kws(kws)
112 .flags(flags)
113 .pipe(|cmd| self.run_with(cmd, self.default_mode(), &STRAT_ASK))
114 .await
115 }
116
117 async fn s(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
119 Cmd::with_sudo(["emerge"])
120 .kws(kws)
121 .flags(flags)
122 .pipe(|cmd| self.run_with(cmd, self.default_mode(), &STRAT_INSTALL))
123 .await
124 }
125
126 async fn sc(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
129 Cmd::with_sudo(["eclean-dist"])
130 .kws(kws)
131 .flags(flags)
132 .pipe(|cmd| self.run_with(cmd, self.default_mode(), &STRAT_INTERACTIVE))
133 .await
134 }
135
136 async fn scc(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
138 self.sc(kws, flags).await
139 }
140
141 async fn si(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
143 let kws = kws.iter().map(|kw| format!("^{kw}$")).collect_vec();
144 self.run(Cmd::new(["emerge", "-s"]).kws(kws).flags(flags))
145 .await
146 }
147
148 async fn ss(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
151 self.run(Cmd::new(["qsearch"]).kws(kws).flags(flags)).await
152 }
153
154 async fn su(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
156 Cmd::with_sudo(["emerge", "-uDN"])
157 .kws(if kws.is_empty() { &["@world"][..] } else { kws })
158 .flags(flags)
159 .pipe(|cmd| self.run_with(cmd, self.default_mode(), &STRAT_INSTALL))
160 .await
161 }
162
163 async fn suy(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
166 self.sy(&[], flags).await?;
167 self.su(kws, flags).await
168 }
169
170 async fn sy(&self, kws: &[&str], flags: &[&str]) -> Result<()> {
172 self.run(Cmd::with_sudo(["emerge", "--sync"]).flags(flags))
173 .await?;
174 if !kws.is_empty() {
175 self.s(kws, flags).await?;
176 }
177 Ok(())
178 }
179}