use std::collections::{HashMap, HashSet};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Source {
System,
Flatpak,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Origin {
Repo,
Local,
Orphaned,
Unknown,
}
#[derive(Clone)]
pub struct Package {
pub name: String,
pub version: String,
pub candidate: Option<String>,
pub installed_size: u64,
pub description: String,
pub details: Option<String>,
pub manual: bool,
pub source: Source,
pub remote: Option<String>,
pub origin: Origin,
pub install_epoch: Option<i64>,
pub install_date: Option<String>,
}
pub struct World {
pub packages: HashMap<String, Package>,
pub deps: HashMap<String, Vec<String>>,
pub rdeps: HashMap<String, Vec<String>>,
pub manual: HashSet<String>,
pub install_log: Vec<(i64, String)>,
}
#[cfg(test)]
impl World {
pub fn from_edges(edges: &[(&str, &str)], manual: &[&str]) -> World {
let mut world = World::empty();
let add = |world: &mut World, name: &str| {
world
.packages
.entry(name.to_string())
.or_insert_with(|| Package {
name: name.to_string(),
version: "1.0".into(),
candidate: None,
installed_size: 100,
description: format!("{name} description"),
details: None,
manual: false,
source: Source::System,
remote: None,
origin: Origin::Repo,
install_epoch: None,
install_date: None,
});
};
for (dependent, dependency) in edges {
add(&mut world, dependent);
add(&mut world, dependency);
world
.deps
.entry(dependent.to_string())
.or_default()
.push(dependency.to_string());
world
.rdeps
.entry(dependency.to_string())
.or_default()
.push(dependent.to_string());
}
for name in manual {
add(&mut world, name);
world.manual.insert(name.to_string());
if let Some(p) = world.packages.get_mut(*name) {
p.manual = true;
}
}
world
}
}
impl World {
pub fn empty() -> Self {
World {
packages: HashMap::new(),
deps: HashMap::new(),
rdeps: HashMap::new(),
manual: HashSet::new(),
install_log: Vec::new(),
}
}
pub fn is_manual(&self, pkg: &str) -> bool {
self.manual.contains(pkg)
}
pub fn is_upgradable(&self, pkg: &str) -> bool {
self.packages
.get(pkg)
.map(|p| p.candidate.is_some())
.unwrap_or(false)
}
pub fn rdeps_of(&self, pkg: &str) -> &[String] {
self.rdeps.get(pkg).map(Vec::as_slice).unwrap_or(&[])
}
pub fn deps_of(&self, pkg: &str) -> &[String] {
self.deps.get(pkg).map(Vec::as_slice).unwrap_or(&[])
}
pub fn rdep_count(&self, pkg: &str) -> usize {
self.rdeps.get(pkg).map(Vec::len).unwrap_or(0)
}
pub fn all_names_sorted(&self) -> Vec<String> {
let mut names: Vec<String> = self.packages.keys().cloned().collect();
names.sort();
names
}
pub fn upgradable_names_sorted(&self) -> Vec<String> {
let mut names: Vec<String> = self
.packages
.values()
.filter(|p| p.candidate.is_some())
.map(|p| p.name.clone())
.collect();
names.sort();
names
}
}