use std::collections::BTreeSet;
use sandogasa_inventory::{Inventory, Package};
pub fn intersect(base: Inventory, filter: &BTreeSet<String>) -> Vec<Package> {
base.package
.into_iter()
.filter(|p| filter.contains(&p.name))
.collect()
}
pub fn merge_packages(
path: &str,
packages: Vec<Package>,
meta: &sandogasa_inventory::InventoryMeta,
) -> Result<usize, String> {
let mut inventory = if std::path::Path::new(path).exists() {
sandogasa_inventory::load(path)?
} else {
Inventory {
inventory: meta.clone(),
package: Vec::new(),
}
};
let existing: BTreeSet<String> = inventory.package.iter().map(|p| p.name.clone()).collect();
let mut added = 0;
for pkg in packages {
if !existing.contains(&pkg.name) {
inventory.package.push(pkg);
added += 1;
}
}
inventory.package.sort_by(|a, b| a.name.cmp(&b.name));
sandogasa_inventory::save(&inventory, path)?;
Ok(added)
}
#[cfg(test)]
mod tests {
use super::*;
fn inventory(entries: &[(&str, Option<&str>)]) -> Inventory {
Inventory {
inventory: sandogasa_inventory::InventoryMeta {
name: "t".into(),
description: "t".into(),
maintainer: "t".into(),
labels: Vec::new(),
workloads: Default::default(),
private_fields: Vec::new(),
synced: None,
},
package: entries
.iter()
.map(|(name, reason)| Package {
name: name.to_string(),
reason: reason.map(str::to_string),
..Default::default()
})
.collect(),
}
}
#[test]
fn intersection_keeps_base_metadata() {
let base = inventory(&[
(
"rust-clap",
Some("runtime dependency (rawhide): src:ripgrep requires crate(clap)"),
),
("glibc", Some("everything needs it")),
]);
let filter: BTreeSet<String> = ["rust-clap".to_string()].into();
let out = intersect(base, &filter);
assert_eq!(out.len(), 1);
assert_eq!(out[0].name, "rust-clap");
assert!(out[0].reason.as_deref().unwrap().contains("src:ripgrep"));
}
#[test]
fn merge_accumulates_and_leaves_existing_entries_alone() {
let dir = tempfile::tempdir().unwrap();
let dest = dir.path().join("essentials.toml");
let dest = dest.to_str().unwrap();
let meta = inventory(&[]).inventory;
let first = inventory(&[("rust-clap", Some("from build deps"))]).package;
assert_eq!(merge_packages(dest, first, &meta).unwrap(), 1);
let second = inventory(&[("rust-clap", Some("different")), ("rust-syn", None)]).package;
assert_eq!(merge_packages(dest, second, &meta).unwrap(), 1);
let merged = sandogasa_inventory::load(dest).unwrap();
let names: Vec<&str> = merged.package.iter().map(|p| p.name.as_str()).collect();
assert_eq!(names, ["rust-clap", "rust-syn"]);
assert_eq!(merged.package[0].reason.as_deref(), Some("from build deps"));
}
}