1use std::cmp::Ordering;
3
4use terminal_size::{terminal_size, Height, Width};
5
6use crate::error::AptErrors;
7use crate::{config, Cache, DepFlags, Package};
8
9pub fn terminal_height() -> usize {
14 if let Some((_, Height(rows))) = terminal_size() {
15 usize::from(rows)
16 } else {
17 24
18 }
19}
20
21pub fn terminal_width() -> usize {
26 if let Some((Width(cols), _)) = terminal_size() {
27 usize::from(cols)
28 } else {
29 80
30 }
31}
32
33pub fn cmp_versions(ver1: &str, ver2: &str) -> Ordering {
48 let result = raw::cmp_versions(ver1, ver2);
49 match result {
50 _ if result < 0 => Ordering::Less,
51 _ if result == 0 => Ordering::Equal,
52 _ => Ordering::Greater,
53 }
54}
55
56pub enum DiskSpace {
58 Require(u64),
60 Free(u64),
62}
63
64pub enum NumSys {
66 Binary,
68 Decimal,
70}
71
72pub fn unit_str(val: u64, base: NumSys) -> String {
84 let val = val as f64;
85 let (num, tera, giga, mega, kilo) = match base {
86 NumSys::Binary => (1024.0_f64, "TiB", "GiB", "MiB", "KiB"),
87 NumSys::Decimal => (1000.0_f64, "TB", "GB", "MB", "KB"),
88 };
89
90 let powers = [
91 (num.powi(4), tera),
92 (num.powi(3), giga),
93 (num.powi(2), mega),
94 (num, kilo),
95 ];
96
97 for (divisor, unit) in powers {
98 if val > divisor {
99 return format!("{:.2} {unit}", val / divisor);
100 }
101 }
102 format!("{val} B")
103}
104
105pub fn time_str(seconds: u64) -> String {
107 if seconds > 60 * 60 * 24 {
108 return format!(
109 "{}d {}h {}min {}s",
110 seconds / 60 / 60 / 24,
111 (seconds / 60 / 60) % 24,
112 (seconds / 60) % 60,
113 seconds % 60,
114 );
115 }
116 if seconds > 60 * 60 {
117 return format!(
118 "{}h {}min {}s",
119 (seconds / 60 / 60) % 24,
120 (seconds / 60) % 60,
121 seconds % 60,
122 );
123 }
124 if seconds > 60 {
125 return format!("{}min {}s", (seconds / 60) % 60, seconds % 60,);
126 }
127 format!("{seconds}s")
128}
129
130pub fn get_apt_progress_string(percent: f32, output_width: u32) -> String {
142 raw::get_apt_progress_string(percent, output_width)
143}
144
145pub fn apt_lock() -> Result<(), AptErrors> {
161 config::init_config_system();
162 Ok(raw::apt_lock()?)
163}
164
165pub fn apt_unlock() {
167 config::init_config_system();
168 raw::apt_unlock()
169}
170
171pub fn apt_lock_inner() -> Result<(), AptErrors> {
178 config::init_config_system();
179 Ok(raw::apt_lock_inner()?)
180}
181
182pub fn apt_unlock_inner() {
184 config::init_config_system();
185 raw::apt_unlock_inner()
186}
187
188pub fn apt_is_locked() -> bool {
193 config::init_config_system();
194 raw::apt_is_locked()
195}
196
197pub fn show_broken_pkg(cache: &Cache, pkg: &Package, now: bool) -> Option<String> {
205 if (now && !pkg.is_now_broken()) || (!now && !pkg.is_inst_broken()) {
207 return None;
208 };
209
210 let mut broken_string = String::new();
211
212 broken_string += &format!(" {pkg} :");
213
214 let Some(ver) = (match now {
217 true => pkg.installed(),
218 false => pkg.install_version(),
219 }) else {
220 broken_string += "\n";
221 return Some(broken_string);
222 };
223
224 let indent = pkg.name().len() + 3;
225 let mut first = true;
226
227 for dep in ver.depends_map().values().flatten() {
229 for (i, base_dep) in dep.iter().enumerate() {
230 if !cache.depcache().is_important_dep(base_dep) {
231 continue;
232 }
233
234 let dep_flag = if now { DepFlags::DepGNow } else { DepFlags::DepInstall };
235
236 if cache.depcache().dep_state(base_dep) & dep_flag == dep_flag {
237 continue;
238 }
239
240 if !first {
241 broken_string += &" ".repeat(indent);
242 }
243 first = false;
244
245 if i > 0 {
247 broken_string += &" ".repeat(base_dep.dep_type().as_ref().len() + 3);
248 } else {
249 broken_string += &format!(" {}: ", base_dep.dep_type())
250 }
251
252 broken_string += base_dep.target_package().name();
253
254 if let (Ok(ver_str), Some(comp)) = (base_dep.target_ver(), base_dep.comp_type()) {
255 broken_string += &format!(" ({comp} {ver_str})");
256 }
257
258 let target = base_dep.target_package();
259 if !target.has_provides() {
260 if let Some(target_ver) = target.install_version() {
261 broken_string += &format!(" but {target_ver} is to be installed")
262 } else if target.candidate().is_some() {
263 broken_string += " but it is not going to be installed";
264 } else if target.has_provides() {
265 broken_string += " but it is a virtual package";
266 } else {
267 broken_string += " but it is not installable";
268 }
269 }
270
271 if i + 1 != dep.len() {
272 broken_string += " or"
273 }
274 broken_string += "\n";
275 }
276 }
277 Some(broken_string)
278}
279
280#[cxx::bridge]
281pub(crate) mod raw {
282 unsafe extern "C++" {
283 include!("rust-apt/apt-pkg-c/util.h");
284
285 pub fn cmp_versions(ver1: &str, ver2: &str) -> i32;
294
295 pub fn get_apt_progress_string(percent: f32, output_width: u32) -> String;
297
298 pub fn apt_lock() -> Result<()>;
300
301 pub fn apt_unlock();
303
304 pub fn apt_lock_inner() -> Result<()>;
306
307 pub fn apt_unlock_inner();
309
310 pub fn apt_is_locked() -> bool;
312 }
313}