#[cfg(feature = "cli-support")]
mod display;
#[cfg(feature = "cli-support")]
pub use display::VerifyErrorsDisplay;
use crate::{Hakari, HakariBuilder, explain::HakariExplain};
use guppy::PackageId;
use std::collections::BTreeSet;
impl<'g> HakariBuilder<'g> {
pub fn verify(mut self) -> Result<(), VerifyErrors<'g>> {
self.verify_mode = true;
let hakari = self.compute();
if hakari.output_map.is_empty() {
Ok(())
} else {
let mut dependency_ids = BTreeSet::new();
for ((_, package_id), v) in &hakari.computed_map {
for (_, inner_map) in v.inner_maps() {
if inner_map.len() > 1 {
dependency_ids.insert(*package_id);
}
}
}
Err(VerifyErrors {
hakari: Box::new(hakari),
dependency_ids,
})
}
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct VerifyErrors<'g> {
pub hakari: Box<Hakari<'g>>,
pub dependency_ids: BTreeSet<&'g PackageId>,
}
impl<'g> VerifyErrors<'g> {
pub fn errors<'a>(&'a self) -> impl ExactSizeIterator<Item = HakariExplain<'g, 'a>> + 'a {
let hakari = &self.hakari;
self.dependency_ids
.iter()
.copied()
.map(move |id| HakariExplain::new(hakari, id).expect("package ID is from this graph"))
}
#[cfg(feature = "cli-support")]
pub fn display<'verify>(&'verify self) -> VerifyErrorsDisplay<'g, 'verify> {
VerifyErrorsDisplay::new(self)
}
}
#[cfg(test)]
#[cfg(feature = "cli-support")]
mod cli_support_tests {
use crate::summaries::{DEFAULT_CONFIG_PATH, HakariConfig};
use guppy::MetadataCommand;
#[test]
fn cargo_guppy_verify() {
let graph = MetadataCommand::new()
.build_graph()
.expect("package graph built correctly");
let config_path = graph.workspace().root().join(DEFAULT_CONFIG_PATH);
let config_str = std::fs::read_to_string(&config_path)
.unwrap_or_else(|err| panic!("could not read hakari config at {config_path}: {err}"));
let config: HakariConfig = config_str.parse().unwrap_or_else(|err| {
panic!("could not deserialize hakari config at {config_path}: {err}")
});
let builder = config.builder.to_hakari_builder(&graph).unwrap();
if let Err(errs) = builder.verify() {
panic!("verify failed: {}", errs.display());
}
}
}