use std::collections::HashMap; use std::fs; use std::fs::File; use std::path::Path; use crate::errors::AppResult; #[derive(Debug, Clone)] pub struct PackageFile { pub path: String, pub package: Package, } #[derive(Debug, Clone)] pub struct PackageFiles { files: HashMap>, } #[derive(Debug, Clone)] pub struct Package { pub name: String, pub version: String, } impl Package { pub fn new(name: String, version: String) -> Self { Self { name, version } } pub fn read(path: &Path) -> AppResult { let mut file = File::open(path)?; let mut buffer = Vec::new(); compress_tools::uncompress_archive_file(&mut file, &mut buffer, ".PKGINFO")?; let pkginfo = String::from_utf8(buffer)?; let mut pkgname = String::new(); let mut pkgver = String::new(); for line in pkginfo.lines() { let line = line.trim(); if line.starts_with("pkgname") { pkgname = line.split('=').nth(1).unwrap().trim().to_string(); } else if line.starts_with("pkgver") { pkgver = line.split('=').nth(1).unwrap().trim().to_string(); } } Ok(PackageFile { path: path.display().to_string(), package: Package::new(pkgname, pkgver), }) } } impl PackageFiles { pub fn new() -> Self { Self { files: HashMap::new(), } } pub fn add(&mut self, file: PackageFile) { self.files .entry(file.clone().package.name) .or_default() .push(file); } pub fn scan(&mut self, path: &Path) -> AppResult<()> { for entry in fs::read_dir(path)? { let entry = entry?; let path = entry.path(); let path_display = path.display().to_string(); if path.is_file() && path_display.contains(".pkg.tar.") && !path_display.ends_with(".sig") { let file = Package::read(&path)?; self.add(file); } } Ok(()) } pub fn prune(&mut self, keep: u8) -> AppResult { let mut to_delete = Vec::new(); for (_, files) in self.files.iter_mut() { files.sort_by(|a, b| b.package.version.cmp(&a.package.version)); to_delete.extend(files.iter().skip(keep as usize)); } for file in &to_delete { fs::remove_file(&file.path)?; } Ok(to_delete.len()) } }