1use std::collections::{BTreeMap, BTreeSet};
2
3use color_eyre::Result;
4use color_eyre::eyre::eyre;
5use regex::Regex;
6use serde::{Deserialize, Serialize};
7
8use crate::cmd::{run_command, run_command_for_stdout};
9use crate::prelude::*;
10
11#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, derive_more::Display)]
12pub struct Xbps;
13
14#[derive(Debug, Serialize, Deserialize, Default)]
15#[serde(deny_unknown_fields)]
16pub struct XbpsConfig {}
17
18#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
19#[serde(deny_unknown_fields)]
20pub struct XbpsPackageOptions {}
21
22#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
23#[serde(deny_unknown_fields)]
24pub struct XbpsRepoOptions {}
25
26impl Backend for Xbps {
27 type Config = XbpsConfig;
28 type PackageOptions = XbpsPackageOptions;
29 type RepoOptions = XbpsRepoOptions;
30
31 fn invalid_package_help_text() -> String {
32 String::new()
33 }
34
35 fn is_valid_package_name(_: &str) -> Option<bool> {
36 None
37 }
38
39 fn get_all_packages(_: &Self::Config) -> Result<BTreeSet<String>> {
40 Err(eyre!("unimplemented"))
41 }
42
43 fn get_installed_packages(
44 config: &Self::Config,
45 ) -> Result<std::collections::BTreeMap<String, Self::PackageOptions>> {
46 if Self::version(config).is_err() {
47 return Ok(BTreeMap::new());
48 }
49
50 let stdout = run_command_for_stdout(
51 ["xbps-query", "--list-manual-pkgs"],
52 Perms::Same,
53 StdErr::Show,
54 )?;
55
56 let re = Regex::new(r"-[^-]*$")?;
58
59 let packages = stdout
60 .lines()
61 .map(|line| {
62 (
63 re.replace_all(line, "").to_string(),
64 Self::PackageOptions {},
65 )
66 })
67 .collect();
68
69 Ok(packages)
70 }
71
72 fn install_packages(
73 packages: &std::collections::BTreeMap<String, Self::PackageOptions>,
74 no_confirm: bool,
75 _: &Self::Config,
76 ) -> Result<()> {
77 if !packages.is_empty() {
78 run_command(
79 ["xbps-install", "--sync"]
80 .into_iter()
81 .chain(Some("--yes").filter(|_| no_confirm))
82 .chain(packages.keys().map(String::as_str)),
83 Perms::Sudo,
84 )?;
85 }
86
87 Ok(())
88 }
89
90 fn uninstall_packages(
91 packages: &BTreeSet<String>,
92 no_confirm: bool,
93 _: &Self::Config,
94 ) -> Result<()> {
95 if !packages.is_empty() {
96 run_command(
97 ["xbps-remove", "--recursive"]
98 .into_iter()
99 .chain(Some("--yes").filter(|_| no_confirm))
100 .chain(packages.iter().map(String::as_str)),
101 Perms::Sudo,
102 )?;
103 }
104
105 Ok(())
106 }
107
108 fn update_packages(
109 packages: &BTreeSet<String>,
110 no_confirm: bool,
111 _: &Self::Config,
112 ) -> Result<()> {
113 if !packages.is_empty() {
114 run_command(
115 ["xbps-install", "--sync", "--update"]
116 .into_iter()
117 .chain(Some("--yes").filter(|_| no_confirm))
118 .chain(packages.iter().map(String::as_str)),
119 Perms::Sudo,
120 )?;
121 }
122
123 Ok(())
124 }
125
126 fn update_all_packages(no_confirm: bool, _: &Self::Config) -> Result<()> {
127 let update = || {
128 run_command(
129 ["xbps-install", "--sync", "--update"]
130 .into_iter()
131 .chain(Some("--yes").filter(|_| no_confirm)),
132 Perms::Sudo,
133 )
134 };
135
136 update()?;
139 update()
140 }
141
142 fn clean_cache(config: &Self::Config) -> Result<()> {
143 Self::version(config).map_or(Ok(()), |_| {
144 run_command(
145 ["xbps-remove", "--clean-cache", "--remove-orphans"],
146 Perms::Sudo,
147 )
148 })
149 }
150
151 fn get_installed_repos(_: &Self::Config) -> Result<BTreeMap<String, Self::RepoOptions>> {
152 Ok(BTreeMap::new())
153 }
154
155 fn add_repos(
156 repos: &BTreeMap<String, Self::RepoOptions>,
157 _: bool,
158 _: &Self::Config,
159 ) -> Result<()> {
160 if repos.is_empty() {
161 Ok(())
162 } else {
163 Err(eyre!("unimplemented"))
164 }
165 }
166
167 fn remove_repos(repos: &BTreeSet<String>, _: bool, _: &Self::Config) -> Result<()> {
168 if repos.is_empty() {
169 Ok(())
170 } else {
171 Err(eyre!("unimplemented"))
172 }
173 }
174
175 fn version(_: &Self::Config) -> Result<String> {
176 run_command_for_stdout(["xbps-query", "--version"], Perms::Same, StdErr::Show)
177 }
178}